Conceitos Java
Conceitos Java
2. Spring Framework
● Experiência: Você tem experiência com Spring Boot, Spring Data, e Mockito em suas funções mais recentes.
● Preparação:
● Spring Boot: Explore mais sobre a configuração automática e como criar APIs REST. Você já trabalhou com isso ao
atualizar o cadastro de contas.
● Spring Data: Revise como você usou o Spring Data para interagir com o banco de dados, especialmente em suas tarefas
de manutenção.
4. Integração Contínua
● Experiência: Embora não tenha mencionado diretamente, a utilização de Mockito e JUnit sugere que você pode ter experiência
em testes automatizados.
● Preparação:
● Aprenda a configurar um pipeline de CI/CD com Jenkins para automatizar a construção e os testes de suas aplicações.
● Pratique escrever testes unitários e de integração para suas classes de serviço.
6. HTML5 e JavaScript
● Experiência: Você utilizou JSP e AJAX em seus projetos.
● Preparação:
● Revise como usar HTML5 para criar formulários e interagir com APIs.
● Pratique a manipulação do DOM usando JavaScript e como integrar isso com suas aplicações Angular.
7. Práticas de Programação
● Experiência: Você tem experiência em desenvolvimento ágil e com frameworks que seguem o padrão MVC.
● Preparação:
● Estude padrões de design relevantes, como Singleton e Factory, e como eles se aplicam ao seu trabalho com Spring.
● Pratique a escrita de testes automatizados para garantir a qualidade do seu código.
8. Soft Skills
● Experiência: Sua atuação em equipes de desenvolvimento em empresas como Bradesco e Elabbora mostra que você tem
experiência em trabalho colaborativo.
● Preparação:
● Prepare-se para discutir sua experiência em ambientes ágeis e como você contribuiu para a equipe.
● Pense em exemplos de como você comunicou soluções técnicas para stakeholders ou colegas.
1. Desenvolvimento JEE (Java EE)
● Experiência: O Apache Tomcat é um contêiner de servlets que suporta Java EE, e você pode utilizá-lo para desenvolver e
implantar aplicações web.
● Preparação:
● Revise como configurar o Tomcat, incluindo a criação de arquivos web.xml e a configuração de contextos.
● Explore como o Tomcat gerencia o ciclo de vida de Servlets e JSPs, e como você pode otimizar o desempenho de
aplicações implantadas nele.
2. Spring Framework
● Experiência: Você pode ter usado o Tomcat como servidor de aplicação para suas aplicações Spring Boot.
● Preparação:
● Aprenda como o Spring Boot facilita a configuração do Tomcat embutido, permitindo que você execute aplicações Spring
sem configuração adicional.
● Revise como você pode personalizar a configuração do Tomcat dentro de um projeto Spring Boot.
4. Integração Contínua
● Experiência: Se você usou o Tomcat em ambientes de desenvolvimento, você pode integrar isso em um pipeline de CI/CD.
● Preparação:
● Configure o Jenkins para implantar automaticamente suas aplicações no Tomcat após a construção e os testes.
6. HTML5 e JavaScript
● Experiência: Você utilizou JSP e AJAX em suas aplicações.
● Preparação:
● Explore como você pode usar HTML5 e JavaScript para melhorar a interação do usuário nas aplicações que você já
desenvolveu, especialmente em projetos que utilizam Tomcat.
7. Práticas de Programação
● Experiência: Você já trabalha com padrões de design e boas práticas de programação.
● Preparação:
● Considere como implementar padrões de design em aplicações que você implantou no Tomcat, e como isso pode
melhorar a manutenibilidade do código.
8. Soft Skills
● Experiência: Sua experiência em ambientes de desenvolvimento ágil em empresas como Bradesco e Elabbora é valiosa.
● Preparação:
● Prepare-se para discutir como você colaborou em equipes que utilizavam Tomcat e Spring, e como isso impactou a
entrega de projetos.
Perguntas e Respostas
"Tenho mais de [X anos] de experiência com Java, tendo trabalhado com várias versões, incluindo Java 8, Java 11 e Java 17. Em minha
posição atual no Bradesco, estou utilizando Java 8 e Java 17 para desenvolver e manter sistemas críticos. Também tenho experiência
com Java 11 durante a migração do serviço de PIX para a nuvem."
"Spring é um framework que facilita o desenvolvimento de aplicações Java, oferecendo uma abordagem leve e modular. Java EE, por
outro lado, é uma especificação que fornece um conjunto completo de APIs e serviços para o desenvolvimento de aplicações
corporativas. Enquanto o Spring permite um desenvolvimento mais flexível e ágil, o Java EE pode ser mais rígido em sua estrutura. Em
minha experiência, utilizei ambos, mas prefiro o Spring por sua simplicidade e facilidade de integração."
"Eu sigo boas práticas de programação, como o uso de padrões de design e princípios SOLID. Além disso, escrevo testes unitários e de
integração utilizando JUnit e Mockito, o que me permite garantir que o código funcione como esperado. Em meu trabalho anterior,
implementei testes automatizados que ajudaram a reduzir bugs em produção e melhoraram a confiança na entrega de novas
funcionalidades."
"Sim, tenho experiência com integração contínua, especialmente utilizando Jenkins. Em meu projeto de migração do PIX para a nuvem,
configurei um pipeline que automatizava a construção do projeto, execução de testes e implantação no ambiente de produção. Isso não
apenas acelerou o processo de desenvolvimento, mas também melhorou a qualidade do código, permitindo que a equipe detectasse
problemas mais cedo."
"Quando enfrento problemas de desempenho, começo analisando os logs e métricas da aplicação para identificar gargalos. Em um
projeto anterior, onde trabalhei com Spring Boot e PostgreSQL, utilizei ferramentas de profiling para identificar consultas SQL lentas e
otimizei índices no banco de dados. Além disso, reviso o código para garantir que as melhores práticas de programação estejam sendo
seguidas, como o uso eficiente de caches com Redis."
6. Você pode descrever uma situação em que teve que trabalhar em equipe para resolver um problema?
Resposta Sugerida:
"Em um projeto de atualização do cadastro de contas, nossa equipe enfrentou um desafio com a integração de APIs. Organizei uma
reunião para discutir as dificuldades e sugeri dividir o trabalho em tarefas menores. Trabalhando em conjunto, conseguimos identificar o
problema e implementar uma solução que melhorou a comunicação entre os serviços. Essa abordagem colaborativa não apenas
resolveu o problema, mas também fortaleceu a equipe."
7. Quais são suas experiências com Angular e como você o utilizou em seus projetos?
Resposta Sugerida:
"Trabalhei com Angular 5 em projetos anteriores, desenvolvendo interfaces para sistemas de saneamento. Utilizei componentes e
serviços para criar uma aplicação responsiva e interativa. Em um dos projetos, implementei a comunicação com uma API REST
desenvolvida em Spring Boot, o que permitiu que a interface do usuário fosse atualizada dinamicamente com dados do servidor."
"Eu me mantenho atualizado através de cursos online, leitura de blogs e participação em comunidades de desenvolvedores. Também
sigo as atualizações do Java e do Spring, além de participar de meetups e conferências sempre que possível. Acredito que a
aprendizagem contínua é essencial para um desenvolvedor, especialmente em um campo tão dinâmico."
Java EE (JEE)
O que é Java EE?
Java EE (Java Platform, Enterprise Edition) é uma plataforma que fornece um conjunto de especificações e APIs para o desenvolvimento
de aplicações corporativas em Java. Ela é projetada para facilitar o desenvolvimento de aplicações escaláveis, seguras e robustas.
Arquitetura do Java EE
A arquitetura do Java EE é baseada em uma abordagem em camadas, que geralmente inclui:
Vantagens do Java EE
● Escalabilidade: Suporta aplicações de grande escala e alta disponibilidade.
● Segurança: Fornece recursos de segurança integrados, como autenticação e autorização.
● Transações: Gerencia transações de forma automática, garantindo a integridade dos dados.
Enterprise JavaBeans (EJB)
O que são EJBs?
Enterprise JavaBeans (EJB) são componentes de software que encapsulam a lógica de negócios de uma aplicação Java EE. EJBs
permitem que você crie aplicações distribuídas e escaláveis, facilitando o desenvolvimento de sistemas complexos.
Tipos de EJB
1. Session Beans: Representam uma única sessão de um cliente. Podem ser de dois tipos:
● Stateless: Não mantém estado entre as chamadas. Ideal para operações que não requerem informações de sessão.
● Exemplo: Um bean que realiza cálculos matemáticos.
● Stateful: Mantém estado entre as chamadas. Ideal para operações que requerem informações de sessão.
● Exemplo: Um bean que gerencia o carrinho de compras de um usuário.
2. Message-Driven Beans (MDB): São usados para processar mensagens assíncronas de sistemas de mensagens, como JMS
(Java Message Service).
● Exemplo: Um MDB que processa pedidos de compra recebidos de uma fila.
import javax.ejb.Stateless;
@Stateless
public class CalculatorBean {
Exemplo de JPA
1. Dependências
Primeiro, você precisa adicionar as dependências necessárias ao seu projeto. Se você estiver usando Maven, adicione o seguinte ao seu
pom.xml:
xml
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version> <!-- ou a versão mais recente -->
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.30.Final</version> <!-- ou a versão mais recente -->
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.30.Final</version> <!-- ou a versão mais recente -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.10</version> <!-- ou a versão mais recente -->
</dependency>
2. Configuração do persistence.xml
Crie um arquivo chamado persistence.xml na pasta src/main/resources/META-INF. Este arquivo configura a unidade de
persistência:
xml
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="my-persistence-unit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.example.model.User</class> <!-- Classe da entidade -->
<properties>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/mydb"/>
<property name="javax.persistence.jdbc.user" value="myuser"/>
<property name="javax.persistence.jdbc.password" value="mypassword"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/> <!-- Para criar ou atualizar o esquema -->
</properties>
</persistence-unit>
</persistence>
3. Criando a Entidade
Agora, vamos criar uma entidade User que será mapeada para uma tabela no banco de dados:
java
package com.example.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Getters e Setters
public Long getId() {
return id;
}
4. Operações de Persistência
Agora, vamos criar uma classe de serviço para realizar operações de persistência usando JPA:
package com.example.service;
import com.example.model.User;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
5. Usando o Serviço
Por fim, você pode usar a classe UserService para adicionar e recuperar usuários:
java
// Recuperando um usuário
User retrievedUser = userService.getUser(1L);
System.out.println("User Name: " + retrievedUser.getName());
System.out.println("User Email: " + retrievedUser.getEmail());
}
}
A diferença entre Stateless e Stateful em Enterprise JavaBeans (EJB) é fundamental para entender como gerenciar o estado em
aplicações Java EE. Vamos explorar cada um deles em detalhes.
Características
● Sem Estado: Não armazenam informações do cliente entre as chamadas. Cada invocação é independente.
● Escalabilidade: Podem ser facilmente escalados, pois não precisam manter informações de estado. O servidor pode reutilizar
instâncias de beans para atender a diferentes clientes.
● Desempenho: Geralmente têm desempenho melhor em comparação aos Stateful Beans, pois não precisam gerenciar o estado do
cliente.
Exemplos de Uso
● Serviços de Cálculo: Um bean que realiza operações matemáticas (como adição ou subtração) que não requerem informações de
estado do cliente.
● Serviços de Autenticação: Um bean que verifica credenciais de login, onde cada solicitação é independente.
import javax.ejb.Stateless;
@Stateless
public class CalculatorBean {
Características
● Com Estado: Retêm informações do cliente durante a sessão. O estado é mantido até que o bean seja removido ou a sessão
expire.
● Gerenciamento de Sessão: Ideal para operações que requerem informações de sessão, como carrinhos de compras ou fluxos de
trabalho.
● Desempenho: Podem ter desempenho inferior em comparação aos Stateless Beans, pois precisam gerenciar o estado do cliente.
Exemplos de Uso
● Carrinho de Compras: Um bean que mantém informações sobre os itens que um usuário adicionou ao seu carrinho durante uma
sessão de compras.
● Fluxos de Trabalho: Um bean que gerencia o estado de um processo de negócios em várias etapas.
import javax.ejb.Stateful;
@Stateful
public class ShoppingCartBean {
Struts Action → 2. EJB (via Local Interface (Facade Local)) → 3. Business Logic in EJB (Facade Bean) → 4. DAO → 5. Return to EJB →
6. Return to Struts Action → 7. JSP View
Considerações Adicionais
Transações: As transações geralmente são gerenciadas no nível do EJB.
Exceções: É importante tratar exceções em cada camada para garantir que a aplicação se comporte de maneira previsível.
Injeção de Dependências: Dependendo do framework, a injeção de dependências pode ser usada para gerenciar a instância dos EJBs.
Essa ordem e estrutura ajudam a manter uma separação clara de preocupações, facilitando a manutenção e a escalabilidade da
aplicação.
A arquitetura que você descreveu é um exemplo clássico de Arquitetura em Camadas (ou Layered Architecture) com um padrão de MVC
(Model-View-Controller). Vamos detalhar cada um dos componentes e como eles se encaixam nessa arquitetura.
Estrutura da Arquitetura
1. Camada de Apresentação (Presentation Layer):
● Struts Action: O controlador Struts atua como um intermediário entre a interface do usuário (JSP) e a lógica de negócios.
Ele recebe as requisições do usuário, processa as entradas e decide qual lógica de negócios deve ser invocada.
● JSP View: A camada de apresentação finaliza o fluxo, renderizando a interface do usuário com os dados recebidos.
2. Camada de Lógica de Negócios (Business Logic Layer):
● Service Layer (EJB): A Action do Struts invoca um EJB para processar a lógica de negócios. Essa camada é responsável
por implementar as regras de negócio e orquestrar as operações necessárias.
● Business Logic in EJB: O EJB contém a lógica de negócios específica e pode chamar outros serviços ou acessar dados
através de DAOs.
3. Camada de Acesso a Dados (Data Access Layer):
● Data Access Object (DAO): Essa camada encapsula a lógica de acesso ao banco de dados. O EJB chama o DAO para
realizar operações de CRUD, isolando a lógica de acesso a dados da lógica de negócios.
Padrões Utilizados
● MVC (Model-View-Controller):
● Model: Representado pela camada de lógica de negócios e pela camada de acesso a dados (EJB e DAO).
● View: Representada pelas JSPs que apresentam a interface do usuário.
● Controller: Representado pelas Actions do Struts que gerenciam o fluxo de controle.
● Facade Pattern:
● O uso de interfaces locais (Local e LocalHome) para acessar EJBs pode ser considerado uma implementação do padrão
Facade, que simplifica a interação com a lógica de negócios.
Considerações Adicionais
● Transações: A gestão de transações no nível do EJB é uma prática comum em aplicações empresariais, permitindo que as
operações sejam atômicas e consistentes.
● Tratamento de Exceções: A implementação de tratamento de exceções em cada camada garante que a aplicação se comporte de
maneira previsível e que os erros sejam gerenciados adequadamente.
● Injeção de Dependências: A injeção de dependências pode ser utilizada para gerenciar a criação e o ciclo de vida dos EJBs,
facilitando a configuração e a manutenção do código.
Ao considerar uma evolução tecnológica para a arquitetura que você descreveu, é importante focar em soluções que promovam
escalabilidade, manutenibilidade, flexibilidade e que se alinhem com as práticas modernas de desenvolvimento. Aqui estão algumas
arquiteturas e abordagens que você pode considerar:
1. Microservices Architecture
● Descrição: Em vez de uma aplicação monolítica, você pode dividir a aplicação em serviços menores e independentes que se
comunicam entre si através de APIs. Cada microserviço pode ser desenvolvido, implantado e escalado de forma independente.
● Vantagens:
● Escalabilidade: Cada microserviço pode ser escalado de forma independente, permitindo que você atenda a diferentes
demandas de forma mais eficiente.
● Tecnologia Independente: Você pode usar diferentes tecnologias e linguagens para diferentes microserviços, dependendo
das necessidades específicas.
● Resiliência: Falhas em um microserviço não afetam toda a aplicação.
● Desafios: A complexidade da gestão de múltiplos serviços e a necessidade de uma boa estratégia de comunicação entre eles.
2. Serverless Architecture
● Descrição: Em uma arquitetura serverless, você utiliza serviços em nuvem que gerenciam a infraestrutura, permitindo que você se
concentre apenas na lógica de negócios. As funções são acionadas por eventos e você paga apenas pelo tempo de execução.
● Vantagens:
● Baixo Custo: Você paga apenas pelo que usa, sem a necessidade de provisionar servidores.
● Escalabilidade Automática: A infraestrutura é gerenciada automaticamente, escalando conforme necessário.
● Desenvolvimento Rápido: Permite que os desenvolvedores se concentrem na lógica de negócios, reduzindo o tempo de
desenvolvimento.
● Desafios: Pode haver limitações em termos de tempo de execução e dependências, além de desafios de monitoramento e
depuração.
3. API-First Architecture
● Descrição: Essa abordagem prioriza o design de APIs desde o início do desenvolvimento. As APIs são vistas como contratos que
definem como os serviços interagem.
● Vantagens:
● Consistência: Facilita a criação de uma interface consistente para diferentes clientes (web, mobile, etc.).
● Facilidade de Integração: Permite que diferentes serviços e aplicações se integrem facilmente.
● Desenvolvimento Paralelo: Equipes diferentes podem trabalhar em paralelo em serviços e front-ends, desde que as APIs
estejam bem definidas.
● Desafios: Requer um bom planejamento e design inicial para garantir que as APIs atendam a todas as necessidades.
4. Event-Driven Architecture
● Descrição: Essa arquitetura é baseada na produção, detecção e reação a eventos. Os componentes da aplicação se comunicam
através de eventos, permitindo um sistema mais reativo e flexível.
● Vantagens:
● Desacoplamento: Os componentes são menos dependentes uns dos outros, facilitando a manutenção e a escalabilidade.
● Reatividade: Permite que a aplicação reaja a eventos em tempo real, melhorando a experiência do usuário.
● Escalabilidade: Os serviços podem ser escalados de forma independente com base na carga de eventos.
● Desafios: A complexidade na gestão de eventos e a necessidade de um bom sistema de monitoramento.
5. Containerization (Docker/Kubernetes)
● Descrição: Utilizar contêineres (como Docker) para empacotar e implantar aplicações, orquestrados por plataformas como
Kubernetes.
● Vantagens:
● Consistência: Garante que a aplicação funcione da mesma forma em diferentes ambientes.
● Escalabilidade: Facilita a escalabilidade horizontal e o gerenciamento de recursos.
● Isolamento: Cada contêiner é isolado, permitindo que diferentes versões da aplicação coexistam.
● Desafios: A curva de aprendizado para gerenciar contêineres e orquestração pode ser alta.
1. Generics
Generics em Java permitem que você escreva classes, interfaces e métodos que operam em tipos especificados pelo usuário. A principal
vantagem dos generics é a segurança de tipo (type safety), que ajuda a evitar erros de tipo em tempo de compilação.
Exemplo de Generics
java
public T getItem() {
return item;
}
}
// Uso
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String item = stringBox.getItem(); // type safe
2. Generics Delimitados
Os generics delimitados permitem que você restrinja os tipos que podem ser passados como parâmetros para um tipo genérico.
// Uso
Integer maxInt = max(5, 10); // Retorna 10
String maxStr = max("apple", "banana"); // Retorna "banana"
Neste exemplo, o método max só aceita tipos que implementam a interface Comparable, garantindo que os objetos possam ser
comparados.
3. Wildcards (Curingas)
Os wildcards são usados para indicar que um tipo pode ser qualquer tipo. Existem três formas principais de wildcards:
● <?>: Representa um tipo desconhecido. Por exemplo, List<?> pode ser uma lista de qualquer tipo.
● <? extends T>: Representa um tipo que é uma subclasse de T. Por exemplo, List<? extends Shape> pode ser uma lista de
Shape ou qualquer subclasse de Shape.
● <? super T>: Representa um tipo que é uma superclasse de T. Por exemplo, List<? super Dog> pode ser uma lista de Dog ou
qualquer superclasse de Dog.
Exemplo de Wildcards
java
4. equals() e hashCode()
Os métodos equals() e hashCode() são usados para comparar objetos em Java.
● equals(): Método que verifica se dois objetos são "iguais". O método padrão (da classe Object) compara referências, mas
geralmente é sobrescrito para comparar os valores dos atributos.
● hashCode(): Método que retorna um código hash (um número inteiro) para o objeto. É usado em coleções como HashMap e
HashSet para otimizar a busca de objetos.
Importância
● Performance: hashCode() é geralmente mais rápido do que equals(), pois retorna um valor inteiro, enquanto equals() pode
exigir uma comparação mais detalhada.
● Contratos: Se você sobrescrever equals(), deve também sobrescrever hashCode() para garantir que objetos iguais tenham o
mesmo código hash.
Exemplo
java
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
MyObject myObject = (MyObject) obj;
return Objects.equals(attribute, myObject.attribute);
}
@Override
public int hashCode() {
return Objects.hash(attribute);
}
5. Interface Comparable
A interface Comparable<T> é usada para definir uma ordem natural para os objetos de uma classe. Ela exige a implementação do
método compareTo(T o).
Exemplo de Implementação
java
public class Person implements Comparable<Person> {
private String name;
@Override
public int compareTo(Person other) {
return this.name.compareTo(other.name); // Ordena por nome
}
}
// Uso
List<Person> people = new ArrayList<>();
people.add(new Person("Alice"));
people.add(new Person("Bob"));
Collections.sort(people); // Ordena a lista usando compareTo
Resumo
● Generics: Permitem reuso e segurança de tipo.
● Generics Delimitados: Restringem os tipos que podem ser usados.
● Wildcards: Representam tipos desconhecidos ou limitados.
● equals() e hashCode(): Usados para comparar objetos e otimizar a busca em coleções.
● Comparable: Interface para definir a ordem natural de objetos.
Vamos explorar cada um dos conceitos que você mencionou sobre Interfaces Funcionais, Streams, e Default Methods em Java,
detalhando suas definições, exemplos e usos.
1. Interfaces Funcionais
Interfaces Funcionais são interfaces que possuem exatamente um método abstrato. Elas são uma parte fundamental da programação
funcional em Java e permitem o uso de expressões lambda e referências a métodos.
@FunctionalInterface
public interface MyFunctionalInterface {
void execute();
}
java
a. Predicate<T>
● Descrição: Representa uma função que aceita um argumento e retorna um valor booleano.
● Método Abstrato: boolean test(T t)
● Uso: Comumente usado em métodos que filtram coleções, como removeIf().
java
java
c. Function<T, R>
● Descrição: Representa uma função que aceita um argumento e produz um resultado.
● Método Abstrato: R apply(T t)
● Uso: Usado em operações que transformam valores, como map().
java
3. Streams
Streams são uma sequência de elementos que permitem processar coleções de forma funcional. Eles são imutáveis, processados sob
demanda e não têm índices.
// Uso
MyClass myClass = new MyClass();
myClass.regularMethod(); // Saída: Implementação do método regular.
myClass.defaultMethod(); // Saída: Este é um método padrão.
Resumo
● Interfaces Funcionais: Interfaces com um único método abstrato, usadas com expressões lambda.
● Predicate, Consumer, Function: Principais interfaces funcionais que permitem operações de teste, consumo e transformação de
dados.
● Streams: Permitem o processamento funcional de coleções, com operações intermediárias e terminais.
● Default Methods: Métodos com implementação padrão em interfaces, permitindo evolução sem quebrar implementações
existentes.
Vamos explorar as diferenças e características dos Sets e Maps em Java, incluindo suas implementações mais comuns: HashSet,
TreeSet, LinkedHashSet, HashMap, TreeMap e LinkedHashMap.
1. Set
Um Set é uma coleção que não permite elementos duplicados. Os elementos em um Set não têm uma ordem definida (exceto em
algumas implementações) e não podem ser acessados por índice.
2. Map
Um Map é uma coleção de pares chave/valor, onde cada chave é única. Os elementos em um Map são indexados pela chave, e não têm
uma ordem definida (exceto em algumas implementações).
1. Herança
Herança é um mecanismo que permite que uma classe (subclasse) herde atributos e métodos de outra classe (superclasse). Isso
promove o reuso de código e a criação de hierarquias de classes.
Características da Herança
● Reuso de Código: Permite que subclasses reutilizem métodos e atributos da superclasse, evitando duplicação de código.
● Relação "é um": A subclasse é um tipo da superclasse. Por exemplo, se você tem uma classe Animal e uma subclasse
Cachorro, pode-se dizer que "um cachorro é um animal".
● Generalização e Especialização: A superclasse representa uma generalização, enquanto a subclasse representa uma
especialização. Por exemplo, Animal é uma generalização, e Cachorro e Gato são especializações.
● Limitações: Java não suporta herança múltipla (uma classe não pode herdar de mais de uma classe), mas pode implementar
múltiplas interfaces.
Exemplo de Herança
java
class Animal {
void fazerSom() {
System.out.println("Som de animal");
}
}
// Uso
Animal meuCachorro = new Cachorro();
meuCachorro.fazerSom(); // Saída: Au Au
2. Interface
Uma interface é um contrato que define um conjunto de métodos que uma classe deve implementar. Interfaces não podem conter
implementação de métodos (exceto métodos padrão a partir do Java 8) e são usadas para especificar comportamentos.
Características da Interface
● Contrato: Uma interface define um contrato que as classes implementadoras devem cumprir. Isso garante que as classes
implementem os métodos definidos na interface.
● Relação "cumpre contrato": Uma classe que implementa uma interface "cumpre o contrato" definido por essa interface. Por
exemplo, se uma classe implementa a interface Animal, deve fornecer implementações para os métodos definidos na interface.
● Múltiplas Interfaces: Uma classe pode implementar múltiplas interfaces, permitindo uma forma de herança múltipla.
● Flexibilidade: Interfaces permitem que diferentes classes que não estão relacionadas por herança possam ser tratadas de forma
semelhante.
Exemplo de Interface
java
interface Animal {
void fazerSom();
}
// Uso
Animal meuGato = new Gato();
meuGato.fazerSom(); // Saída: Miau
interface Animal {
void fazerSom();
}
AnimalAbstrato(String nome) {
this.nome = nome;
}
void mostrarNome() {
System.out.println("Nome: " + nome);
}
}
// Uso
Cachorro meuCachorro = new Cachorro("Rex");
meuCachorro.mostrarNome(); // Saída: Nome: Rex
meuCachorro.fazerSom(); // Saída: Au Au
Reuso de Código Sim (métodos e atributos) Não (apenas métodos a serem implementados)
Relação "É um" (subclasses são tipos da "Cumpre contrato" (classes implementam métodos da
superclasse) interface)
Múltiplas Implementações Não (herança única) Sim (uma classe pode implementar várias interfaces)
1. Encapsulamento
Encapsulamento é o princípio de esconder os detalhes internos de uma classe e expor apenas o que é necessário através de uma
interface controlada. Isso protege os dados sensíveis e mantém uma separação clara entre a implementação e o uso da classe.
Características do Encapsulamento
● Acesso Controlado: Usando modificadores de acesso (como private, protected, e public), você pode controlar quem pode
acessar os dados e métodos de uma classe.
● Proteção de Dados: Os dados internos da classe são protegidos contra acesso não autorizado e modificações indesejadas.
● Interface Limpa: A classe fornece métodos públicos (getters e setters) que permitem interagir com os dados de forma controlada.
Exemplo de Encapsulamento
java
// Uso
ContaBancaria conta = new ContaBancaria(1000);
conta.depositar(500);
System.out.println(conta.getSaldo()); // Saída: 1500
2. Herança
Herança é um mecanismo que permite que uma classe (subclasse) herde atributos e métodos de outra classe (superclasse). Isso
promove a reutilização de código e a criação de hierarquias de classes.
Características da Herança
● Reuso de Código: A subclasse pode reutilizar métodos e atributos da superclasse, evitando duplicação de código.
● Relação "é um": A subclasse é um tipo da superclasse. Por exemplo, um Cachorro é um Animal.
● Generalização e Especialização: A superclasse representa uma generalização, enquanto a subclasse representa uma
especialização.
Exemplo de Herança
java
class Animal {
void fazerSom() {
System.out.println("Som de animal");
}
}
// Uso
Animal meuCachorro = new Cachorro();
meuCachorro.fazerSom(); // Saída: Au Au
3. Polimorfismo
Polimorfismo é a capacidade de tratar objetos de classes diferentes de forma uniforme através de uma interface comum. Isso permite
que métodos aceitem objetos de diferentes classes e facilita a substituição dinâmica de implementações.
Características do Polimorfismo
● Substituição de Métodos: Permite que subclasses forneçam implementações específicas para métodos definidos na superclasse.
● Interfaces Comuns: Objetos de diferentes classes podem ser tratados como instâncias de uma classe comum ou interface.
Exemplo de Polimorfismo
java
class Animal {
void fazerSom() {
System.out.println("Som de animal");
}
}
// Uso
Animal[] animais = { new Cachorro(), new Gato() };
for (Animal animal : animais) {
animal.fazerSom(); // Saída: Au Au, Miau
}
4. Abstração
Abstração é o processo de modelar classes e objetos que representam entidades do mundo real de maneira simplificada. Isso permite
focar apenas nos detalhes relevantes para o problema em questão, ignorando complexidades desnecessárias.
Características da Abstração
● Modelagem de Conceitos: Permite representar conceitos complexos de forma mais compreensível.
● Classes Abstratas e Interfaces: Classes abstratas podem ter métodos abstratos (sem implementação) e concretos, enquanto
interfaces definem contratos que as classes devem cumprir.
Exemplo de Abstração
java
// Uso
Forma minhaForma = new Circulo();
minhaForma.desenhar(); // Saída: Desenhando um círculo
Encapsulamento Esconde detalhes internos e protege dados, expondo uma interface controlada.
Herança Permite que classes herdem atributos e métodos de outras classes, promovendo reuso de código.
Polimorfismo Permite que objetos de diferentes classes sejam tratados de forma uniforme através de uma interface comum.
Abstração Modela entidades do mundo real de forma simplificada, focando nos detalhes relevantes.
Vamos explorar em detalhes os conceitos de JPA (Java Persistence API) e Hibernate, abordando suas definições, características e
anotações importantes que você mencionou.
Características da JPA
● Mapeamento Objeto-Relacional (ORM): Permite que você trabalhe com dados em um formato orientado a objetos, enquanto o
banco de dados é relacional.
● Independência de Implementação: JPA é uma especificação, e várias implementações estão disponíveis, sendo o Hibernate a
mais popular.
● Gerenciamento de Entidades: Fornece um mecanismo para gerenciar o ciclo de vida das entidades (inserção, atualização,
exclusão).
2. Hibernate
Hibernate é uma implementação da JPA que fornece uma solução robusta para o mapeamento objeto-relacional. Ele oferece recursos
adicionais além da especificação JPA, como cache de segundo nível e suporte a consultas avançadas.
Características do Hibernate
● Suporte a JPA: Hibernate implementa a especificação JPA, permitindo que você use as anotações e interfaces definidas pela JPA.
● Cache: Hibernate possui suporte a cache de primeiro e segundo nível, melhorando o desempenho das operações de banco de
dados.
● Consultas Avançadas: Oferece HQL (Hibernate Query Language) e Criteria API para consultas mais complexas.
3. EntityManager
O EntityManager é a interface principal da JPA que permite interagir com o contexto de persistência. Ele encapsula uma conexão com o
banco de dados e gerencia o ciclo de vida das entidades.
Características do EntityManager
● Operações CRUD: Permite realizar operações de inserção, remoção e atualização em entidades.
● Contexto de Persistência: Mantém um contexto de persistência onde as entidades são monitoradas.
● Instância por Thread: Em aplicações web, normalmente, uma única instância de EntityManager é mantida por requisição.
4. EntityManagerFactory
O EntityManagerFactory é responsável por criar instâncias de EntityManager. Ele é pesado e deve ser criado uma única vez por
aplicação, sendo reutilizado para criar EntityManagers.
a. @Entity
Define a classe como uma entidade que será mapeada para uma tabela no banco de dados.
java
@Entity
public class Usuario {
// Campos e métodos
}
b. @Id e @GeneratedValue
Define o campo como a chave primária da entidade e especifica como o valor será gerado.
java
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
c. @Transient
Indica que um campo não deve ser mapeado para o banco de dados.
java
@Transient
private String senhaTemporaria;
d. @Column
Define detalhes de mapeamento para uma coluna específica, como nome, tipo e restrições.
java
e. Relacionamentos
● @ManyToOne: Define um relacionamento de muitos para um.
● @OneToMany: Define um relacionamento de um para muitos.
● @OneToOne: Define um relacionamento de um para um.
● @ManyToMany: Define um relacionamento de muitos para muitos, frequentemente usando @JoinTable para especificar uma
tabela intermediária.
java
@ManyToOne
@JoinColumn(name = "grupo_id")
private Grupo grupo;
@OneToMany(mappedBy = "usuario")
private List<Post> posts;
f. @EmbeddedId
Usada para mapear uma chave primária composta.
java
@EmbeddedId
private UsuarioId id;
g. @Query e @NamedQuery
Define consultas personalizadas em repositórios usando JPQL ou SQL nativo.
java
h. @EntityListeners
Especifica classes ou interfaces que respondem a eventos da entidade, como inserção e atualização.
java
@EntityListeners(AuditListener.class)
public class Usuario {
// Campos e métodos
}
i. @Version
Usada para mapear um campo de versão otimista, que ajuda a controlar conflitos de concorrência.
java
@Version
private int versao;
java
@EnableJpaRepositories(basePackages = "com.exemplo.repositorio")
b. @Transactional
Indica que um método deve ser executado dentro de um contexto transacional, garantindo a consistência dos dados.
java
@Transactional
public void salvarUsuario(Usuario usuario) {
entityManager.persist(usuario);
}
c. @Modifying
Usada em conjunto com uma consulta personalizada para indicar que a consulta modifica os dados no banco de dados.
java
@Modifying
@Query("UPDATE Usuario u SET u.nome = :nome WHERE u.id = :id")
void atualizarNome(@Param("id") Long id, @Param("nome") String nome);
Vamos explorar em detalhes o Spring Boot, abordando sua arquitetura, as camadas principais e as anotações importantes que você
mencionou.
Camadas Principais
1. Model
● Descrição: A camada de Model é responsável pelas classes que representam as entidades do banco de dados. Essas
classes são mapeadas usando JPA (Java Persistence API) e refletem as tabelas do banco de dados.
● Exemplo:
● java
●
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Usuario {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
// Getters e Setters
}
●
2. Repository
● Descrição: A camada de Repository é responsável pela interação com o banco de dados. Ela utiliza interfaces do Spring
Data JPA para simplificar o acesso a dados e permite a criação de consultas personalizadas.
● Exemplo:
● java
●
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UsuarioService {
@Autowired
private UsuarioRepository usuarioRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/usuarios")
public class UsuarioController {
@Autowired
private UsuarioService usuarioService;
@PostMapping
public Usuario criarUsuario(@RequestBody Usuario usuario) {
return usuarioService.salvarUsuario(usuario);
}
@GetMapping("/{id}")
public Usuario obterUsuario(@PathVariable Long id) {
return usuarioService.obterUsuarioPorId(id);
}
}
●
2. Anotações Importantes
Anotações de Configuração
● @Configuration: Indica que a classe contém definições de beans para o contexto da aplicação.
● @Profile: Define o perfil de execução em que a classe deve ser instanciada.
● @EnableAutoConfiguration: Habilita a configuração automática do Spring Boot, configurando componentes com base nas
dependências do projeto.
Anotações de Serviço
● @Service: Indica que a classe é um serviço, geralmente contendo lógica de negócios.
● @Repository: Marca a classe como um repositório, permitindo que o Spring trate exceções relacionadas ao acesso a dados.
java
// Model
@Entity
public class Produto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
private double preco;
// Getters e Setters
}
// Repository
public interface ProdutoRepository extends JpaRepository<Produto, Long> {
}
// Service
@Service
public class ProdutoService {
@Autowired
private ProdutoRepository produtoRepository;
// Controller
@RestController
@RequestMapping("/produtos")
public class ProdutoController {
@Autowired
private ProdutoService produtoService;
@PostMapping
public Produto criarProduto(@RequestBody Produto produto) {
return produtoService.salvarProduto(produto);
}
@GetMapping
public List<Produto> listarProdutos() {
return produtoService.listarProdutos();
}
}
Vamos explorar em detalhes os métodos HTTP e os códigos de status que você mencionou, incluindo suas definições e usos comuns.
Métodos HTTP
Os métodos HTTP são usados para indicar a ação que o cliente deseja realizar em um recurso no servidor. Aqui estão os métodos mais
comuns:
1. GET
● Descrição: Solicita dados de um servidor.
● Uso: Usado para recuperar informações, como páginas da web ou dados de uma API.
● Exemplo: Um navegador solicita uma página HTML.
● Idempotente: Sim (repetir a solicitação não altera o estado do recurso).
2. POST
● Descrição: Envia dados ao servidor para processamento.
● Uso: Geralmente usado para enviar informações do cliente, como dados de formulários.
● Exemplo: Enviar um formulário de registro de usuário.
● Idempotente: Não (repetir a solicitação pode criar múltiplos recursos).
3. PUT
● Descrição: Atualiza ou cria um recurso específico no servidor.
● Uso: Envia dados para substituir um recurso existente ou criar um novo.
● Exemplo: Atualizar informações de um usuário existente.
● Idempotente: Sim (repetir a solicitação com os mesmos dados não altera o estado).
4. DELETE
● Descrição: Solicita a exclusão de um recurso específico no servidor.
● Uso: Usado para remover um recurso.
● Exemplo: Excluir um usuário do banco de dados.
● Idempotente: Sim (repetir a solicitação não altera o estado após a primeira exclusão).
5. HEAD
● Descrição: Semelhante ao GET, mas solicita apenas os cabeçalhos da resposta.
● Uso: Útil para verificar a existência de um recurso ou obter informações sobre ele sem baixar o conteúdo.
● Exemplo: Verificar se um recurso está disponível sem baixar.
● Idempotente: Sim.
6. OPTIONS
● Descrição: Solicita informações sobre os métodos de comunicação permitidos para um recurso.
● Uso: Usado para entender as opções disponíveis para interagir com um recurso.
● Exemplo: Verificar quais métodos são suportados por um endpoint.
● Idempotente: Sim.
7. PATCH
● Descrição: Aplica modificações parciais a um recurso.
● Uso: Útil para fazer pequenas alterações em um recurso existente.
● Exemplo: Atualizar apenas o nome de um usuário sem enviar todos os dados.
● Idempotente: Não garantido, depende da implementação.
8. CONNECT
● Descrição: Usado para criar uma conexão de rede com um recurso.
● Uso: Geralmente usado para estabelecer uma conexão segura (túnel) através de um proxy.
● Exemplo: Conectar-se a um servidor HTTPS através de um proxy.
9. TRACE
● Descrição: Usado para fins de depuração e diagnóstico.
● Uso: Permite que o cliente veja quais alterações foram feitas à solicitação ao longo do caminho.
● Exemplo: Diagnosticar problemas de rede.
● Idempotente: Sim.
1xx - Informações
● Esses códigos indicam que a solicitação foi recebida e está sendo processada.
● Exemplo:
● 100 Continue: O cliente pode continuar com a solicitação.
2xx - Sucesso
● Esses códigos indicam que a solicitação foi recebida e processada com sucesso.
● Exemplos:
● 200 OK: A solicitação foi bem-sucedida e o conteúdo solicitado está sendo retornado.
● 201 Created: A solicitação resultou na criação de um novo recurso.
● 204 No Content: A solicitação foi bem-sucedida, mas não há conteúdo para retornar.
3xx - Redirecionamento
● Esses códigos indicam que a solicitação precisa ser redirecionada para outro local.
● Exemplos:
● 301 Moved Permanently: O recurso solicitado foi movido permanentemente para um novo local.
● 302 Found (ou 303 See Other): O recurso foi temporariamente movido para um novo local.
● 304 Not Modified: O recurso não foi modificado desde a última solicitação.
a. @EnableDiscoveryClient
● Descrição: Ativa a capacidade de registro e descoberta de serviços. Permite que os serviços se registrem em um servidor de
descoberta, como Eureka, e descubram outros serviços.
● Uso:
● java
●
@SpringBootApplication
@EnableDiscoveryClient
public class MeuServicoApplication {
public static void main(String[] args) {
SpringApplication.run(MeuServicoApplication.class, args);
}
}
●
b. @EnableEurekaServer
● Descrição: Configura um servidor Eureka para registro e descoberta de serviços. O Eureka Server permite que os serviços se
registrem e descubram uns aos outros.
● Uso:
● java
●
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
●
c. @EnableConfigServer
● Descrição: Configura um servidor de configuração centralizada. Permite que os aplicativos busquem suas configurações de um
local centralizado.
● Uso:
● java
●
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
●
d. @EnableFeignClients
● Descrição: Habilita a criação de clientes de serviço declarativos usando o Feign, simplificando a chamada de APIs HTTP entre
serviços.
● Uso:
● java
●
@SpringBootApplication
@EnableFeignClients
public class MeuServicoApplication {
public static void main(String[] args) {
SpringApplication.run(MeuServicoApplication.class, args);
}
}
●
e. @EnableHystrix
● Descrição: Ativa o suporte ao Hystrix, que fornece tolerância a falhas, permitindo que o aplicativo lide com falhas e latências em
chamadas entre serviços.
● Uso:
● java
●
@SpringBootApplication
@EnableHystrix
public class MeuServicoApplication {
public static void main(String[] args) {
SpringApplication.run(MeuServicoApplication.class, args);
}
}
●
f. @EnableCircuitBreaker
● Descrição: Similar ao @EnableHystrix, habilita o suporte a circuit breakers, permitindo que o aplicativo responda de maneira
controlada a falhas em serviços dependentes.
● Uso:
● java
●
@SpringBootApplication
@EnableCircuitBreaker
public class MeuServicoApplication {
public static void main(String[] args) {
SpringApplication.run(MeuServicoApplication.class, args);
}
}
●
g. @EnableZuulProxy
● Descrição: Configura um servidor Zuul, que atua como um gateway de API para roteamento e balanceamento de carga.
● Uso:
● java
●
@SpringBootApplication
@EnableZuulProxy
public class MeuGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(MeuGatewayApplication.class, args);
}
}
●
h. @RefreshScope
● Descrição: Indica que os componentes do Spring devem ser atualizados quando há alterações nas propriedades de configuração.
Permite a atualização dinâmica das configurações.
● Uso:
● java
●
@RefreshScope
@Component
public class MeuComponente {
// Campos e métodos
}
●
i. @EnableOAuth2Client
● Descrição: Habilita o cliente OAuth2 para autenticação e autorização seguras entre microsserviços.
● Uso:
● java
●
@Configuration
@EnableOAuth2Client
public class SecurityConfig {
// Configurações de segurança
}
●
j. @EnableResourceServer
● Descrição: Configura o aplicativo para atuar como um servidor de recursos protegidos, usado em cenários de autenticação e
autorização OAuth2.
● Uso:
● java
●
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
// Configurações do servidor de recursos
}
●
k. @RibbonClient
● Descrição: Utilizada para personalizar as configurações de balanceamento de carga do Ribbon para um cliente específico.
● Uso:
● java
●
l. @EnableSleuth
● Descrição: Habilita o rastreamento de logs distribuídos para monitorar as interações entre os serviços.
● Uso:
● java
●
@SpringBootApplication
@EnableSleuth
public class MeuServicoApplication {
public static void main(String[] args) {
SpringApplication.run(MeuServicoApplication.class, args);
}
}
●
m. @EnableTurbine
● Descrição: Habilita a agregação de métricas e informações de latência de vários serviços, permitindo monitoramento centralizado.
● Uso:
● java
●
@SpringBootApplication
@EnableTurbine
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
●
A Integração Contínua (CI) é uma prática de desenvolvimento de software que envolve a automação do processo de integração de
código, permitindo que os desenvolvedores integrem suas alterações de código em um repositório compartilhado de forma frequente. O
Jenkins é uma das ferramentas mais populares para implementar a integração contínua e entrega contínua (CD).
● Automação de Builds: O código é automaticamente compilado e testado sempre que uma nova alteração é feita.
● Testes Automatizados: Testes unitários e de integração são executados automaticamente para garantir que as alterações não
quebrem a funcionalidade existente.
● Feedback Rápido: Os desenvolvedores recebem feedback imediato sobre a qualidade do código e a integridade do sistema.
● Redução de Risco: A integração contínua ajuda a identificar problemas mais cedo, reduzindo o risco de falhas em produção.
2. O que é Jenkins?
Jenkins é uma ferramenta de automação de código aberto que suporta a construção, teste e implantação de software. É amplamente
utilizado para implementar práticas de integração contínua e entrega contínua.
Características do Jenkins
● Interface Web: Jenkins possui uma interface web intuitiva que permite aos usuários configurar e monitorar jobs (tarefas).
● Extensibilidade: Jenkins possui um ecossistema rico de plugins que permitem integrar com diversas ferramentas e serviços, como
Git, Maven, Docker, e muito mais.
● Pipeline: Permite definir e automatizar o fluxo de trabalho de construção e implantação usando a linguagem de pipeline do
Jenkins (Jenkinsfile).
● Suporte a Várias Linguagens: Jenkins pode ser usado com uma variedade de linguagens de programação e ferramentas de
construção.
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
// Comando para construir o projeto
sh 'mvn clean package'
}
}
stage('Test') {
steps {
// Comando para executar testes
sh 'mvn test'
}
}
stage('Deploy') {
steps {
// Comando para implantar o aplicativo
sh 'deploy.sh'
}
}
}
}
4. Monitoramento e Feedback
● O Jenkins fornece relatórios de construção, incluindo logs e resultados de testes, permitindo que os desenvolvedores vejam
rapidamente o status da integração contínua.
● Você pode configurar notificações (por exemplo, por e-mail ou Slack) para alertar a equipe sobre falhas na construção ou testes.