Pular para conteúdo

Java

Java é uma linguagem de programação de alto nível, orientada a objetos, que foi desenvolvida pela Sun Microsystems (agora propriedade da Oracle) e lançada em 1995. É conhecida por sua portabilidade ("write once, run anywhere"), robustez e ampla adoção em diversos setores da indústria de software.

Características Principais

1. Orientação a Objetos

Java é uma linguagem fortemente orientada a objetos, onde quase tudo é um objeto. Isso promove:

  • Encapsulamento: Ocultação de detalhes de implementação
  • Herança: Reutilização de código através de hierarquias de classes
  • Polimorfismo: Capacidade de objetos assumirem diferentes formas
  • Abstração: Representação de conceitos complexos de forma simplificada

2. Independência de Plataforma

O código Java é compilado para bytecode, que é executado pela Java Virtual Machine (JVM). Isso permite que programas Java sejam executados em qualquer dispositivo que tenha uma JVM, independentemente do sistema operacional subjacente.

3. Gerenciamento Automático de Memória

Java utiliza um coletor de lixo (garbage collector) que gerencia automaticamente a alocação e desalocação de memória, reduzindo a probabilidade de vazamentos de memória e erros de ponteiro nulo.

4. Tipagem Forte e Estática

Java é uma linguagem fortemente tipada, o que significa que o tipo de uma variável é verificado em tempo de compilação, reduzindo erros em tempo de execução.

5. Multithreading

Java oferece suporte nativo para programação concorrente através de threads, permitindo que múltiplas tarefas sejam executadas simultaneamente.

Sintaxe Básica

Estrutura de um Programa Java

// Declaração do pacote
package com.example;

// Importações
import java.util.List;
import java.util.ArrayList;

// Declaração da classe
public class ExemploJava {
    // Variável de instância
    private String mensagem;

    // Construtor
    public ExemploJava(String mensagem) {
        this.mensagem = mensagem;
    }

    // Método
    public void exibirMensagem() {
        System.out.println(mensagem);
    }

    // Método principal (ponto de entrada)
    public static void main(String[] args) {
        ExemploJava exemplo = new ExemploJava("Olá, mundo!");
        exemplo.exibirMensagem();
    }
}

Tipos de Dados

Tipos Primitivos

  • byte: 8 bits, valores de -128 a 127
  • short: 16 bits, valores de -32,768 a 32,767
  • int: 32 bits, valores de -2^31 a 2^31-1
  • long: 64 bits, valores de -2^63 a 2^63-1
  • float: 32 bits, ponto flutuante de precisão simples
  • double: 64 bits, ponto flutuante de precisão dupla
  • char: 16 bits, um único caractere Unicode
  • boolean: true ou false

Tipos de Referência

  • Classes: String, ArrayList, HashMap, etc.
  • Interfaces: List, Map, Set, etc.
  • Arrays: int[], String[], Object[], etc.

Estruturas de Controle

Condicionais

// If-else
if (condicao) {
    // código se verdadeiro
} else if (outraCondicao) {
    // código se a primeira condição for falsa e a segunda verdadeira
} else {
    // código se ambas as condições forem falsas
}

// Switch
switch (variavel) {
    case valor1:
        // código para valor1
        break;
    case valor2:
        // código para valor2
        break;
    default:
        // código padrão
}

Loops

// For
for (int i = 0; i < 10; i++) {
    // código a ser repetido
}

// While
while (condicao) {
    // código a ser repetido enquanto a condição for verdadeira
}

// Do-While
do {
    // código a ser executado pelo menos uma vez
} while (condicao);

// For-each (enhanced for)
for (Tipo elemento : colecao) {
    // código para processar cada elemento
}

Programação Orientada a Objetos em Java

Classes e Objetos

// Definição de uma classe
public class Pessoa {
    // Atributos (variáveis de instância)
    private String nome;
    private int idade;

    // Construtor
    public Pessoa(String nome, int idade) {
        this.nome = nome;
        this.idade = idade;
    }

    // Métodos
    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public void apresentar() {
        System.out.println("Olá, meu nome é " + nome + " e tenho " + idade + " anos.");
    }
}

// Criação e uso de objetos
Pessoa pessoa1 = new Pessoa("João", 30);
pessoa1.apresentar();

Herança

// Classe base
public class Animal {
    protected String nome;

    public Animal(String nome) {
        this.nome = nome;
    }

    public void emitirSom() {
        System.out.println("Som genérico de animal");
    }
}

// Classe derivada
public class Cachorro extends Animal {
    public Cachorro(String nome) {
        super(nome);
    }

    @Override
    public void emitirSom() {
        System.out.println("Au au!");
    }

    public void abanarRabo() {
        System.out.println(nome + " está abanando o rabo");
    }
}

Interfaces

// Definição de uma interface
public interface Voador {
    void voar();
    double getAltitudeMaxima();
}

// Implementação da interface
public class Passaro implements Voador {
    @Override
    public void voar() {
        System.out.println("O pássaro está voando");
    }

    @Override
    public double getAltitudeMaxima() {
        return 1000.0;
    }
}

Polimorfismo

// Uso de polimorfismo
Animal animal1 = new Cachorro("Rex");
Animal animal2 = new Gato("Felix");

animal1.emitirSom(); // Saída: "Au au!"
animal2.emitirSom(); // Saída: "Miau!"

// Lista polimórfica
List<Animal> animais = new ArrayList<>();
animais.add(new Cachorro("Rex"));
animais.add(new Gato("Felix"));

for (Animal animal : animais) {
    animal.emitirSom(); // Chama o método apropriado para cada tipo
}

Recursos Avançados

Generics

// Definição de uma classe genérica
public class Caixa<T> {
    private T conteudo;

    public void adicionar(T conteudo) {
        this.conteudo = conteudo;
    }

    public T obter() {
        return conteudo;
    }
}

// Uso de generics
Caixa<String> caixaDeTexto = new Caixa<>();
caixaDeTexto.adicionar("Olá, mundo!");
String texto = caixaDeTexto.obter();

Caixa<Integer> caixaDeNumero = new Caixa<>();
caixaDeNumero.adicionar(42);
int numero = caixaDeNumero.obter();

Lambdas e Streams (Java 8+)

// Expressões lambda
List<String> nomes = Arrays.asList("Ana", "Carlos", "Bruno", "Diana");

// Ordenação usando lambda
nomes.sort((s1, s2) -> s1.compareTo(s2));

// Filtro usando lambda
List<String> nomesComC = nomes.stream()
    .filter(nome -> nome.startsWith("C"))
    .collect(Collectors.toList());

// Transformação usando lambda
List<Integer> tamanhos = nomes.stream()
    .map(String::length)
    .collect(Collectors.toList());

// Redução usando lambda
int totalCaracteres = nomes.stream()
    .mapToInt(String::length)
    .sum();

Optional (Java 8+)

// Uso de Optional para evitar NullPointerException
public Optional<Usuario> buscarUsuarioPorId(Long id) {
    // Busca no banco de dados
    Usuario usuario = repositorio.findById(id);
    return Optional.ofNullable(usuario);
}

// Consumindo um Optional
Optional<Usuario> resultado = buscarUsuarioPorId(123L);
resultado.ifPresent(usuario -> System.out.println("Usuário encontrado: " + usuario.getNome()));

// Valor padrão se não encontrado
Usuario usuario = resultado.orElse(new Usuario("Usuário Padrão"));

// Lançar exceção se não encontrado
Usuario usuarioEncontrado = resultado.orElseThrow(() -> new UsuarioNaoEncontradoException("Usuário não encontrado"));

Anotações

// Definição de uma anotação personalizada
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MinhaAnotacao {
    String valor() default "";
    int contador() default 0;
}

// Uso de anotações
public class ExemploAnotacao {
    @MinhaAnotacao(valor = "teste", contador = 5)
    public void metodoAnotado() {
        // Implementação
    }

    // Processamento de anotações em tempo de execução
    public static void main(String[] args) throws Exception {
        Method metodo = ExemploAnotacao.class.getMethod("metodoAnotado");
        if (metodo.isAnnotationPresent(MinhaAnotacao.class)) {
            MinhaAnotacao anotacao = metodo.getAnnotation(MinhaAnotacao.class);
            System.out.println("Valor: " + anotacao.valor());
            System.out.println("Contador: " + anotacao.contador());
        }
    }
}

Ecossistema Java

Ferramentas de Build

  • Maven: Gerenciamento de dependências e automação de build
  • Gradle: Sistema de automação de build flexível

Frameworks Populares

  • Spring: Framework para desenvolvimento de aplicações empresariais
  • Hibernate: Framework ORM (Object-Relational Mapping)
  • Jakarta EE (anteriormente Java EE): Plataforma para desenvolvimento de aplicações empresariais
  • Quarkus: Framework para aplicações Java otimizadas para Kubernetes
  • Micronaut: Framework para microserviços e aplicações serverless

Ferramentas de Teste

  • JUnit: Framework para testes unitários
  • Mockito: Framework para criação de objetos mock em testes
  • AssertJ: Biblioteca para asserções fluentes
  • Selenium: Automação de testes de interface do usuário

Java no Projeto

No contexto do nosso projeto de sistema de feedback, Java é utilizado para implementar os seguintes microserviços:

  1. User Management: Gerenciamento de usuários, autenticação e autorização
  2. Feedback Request: Criação e gerenciamento de solicitações de feedback
  3. Feedback Response: Processamento de respostas de feedback

Esses microserviços são implementados usando Spring Boot, que simplifica o desenvolvimento de aplicações Java, fornecendo configurações automáticas e um modelo de programação baseado em convenções.

Exemplo de Implementação com Spring Boot

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    @HasType("ADMIN")
    public Page<UserDTO> listUsers(
            @RequestParam(required = false) String name,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {

        return userService.findUsers(name, PageRequest.of(page, size));
    }

    @PostMapping
    @HasType("ADMIN")
    public ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO) {
        UserDTO createdUser = userService.createUser(userDTO);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }

    @GetMapping("/{id}")
    @HasType("ADMIN")
    public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PutMapping("/{id}")
    @HasType("ADMIN")
    public ResponseEntity<UserDTO> updateUser(
            @PathVariable Long id,
            @RequestBody @Valid UserDTO userDTO) {

        return ResponseEntity.ok(userService.updateUser(id, userDTO));
    }

    @DeleteMapping("/{id}")
    @HasType("ADMIN")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

Conclusão

Java é uma linguagem versátil e robusta que continua sendo amplamente utilizada no desenvolvimento de aplicações empresariais, incluindo sistemas baseados em microserviços. Sua forte tipagem, orientação a objetos e ecossistema maduro a tornam uma escolha sólida para o desenvolvimento de aplicações complexas e de missão crítica.

No contexto do nosso projeto, Java fornece a base para a implementação dos principais microserviços, garantindo confiabilidade, manutenibilidade e escalabilidade do sistema.