<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jeronima Floriano</title>
    <description>The latest articles on Forem by Jeronima Floriano (@jeronimafloriano).</description>
    <link>https://forem.com/jeronimafloriano</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F908177%2F10cc2ef9-f22a-4b14-99db-031034683bc2.jpg</url>
      <title>Forem: Jeronima Floriano</title>
      <link>https://forem.com/jeronimafloriano</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jeronimafloriano"/>
    <language>en</language>
    <item>
      <title>Do Socket ao Spring Boot: entendendo a comunicação via rede em Java</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Tue, 30 Dec 2025 22:38:07 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/do-socket-ao-spring-boot-entendendo-a-comunicacao-via-rede-em-java-11gd</link>
      <guid>https://forem.com/jeronimafloriano/do-socket-ao-spring-boot-entendendo-a-comunicacao-via-rede-em-java-11gd</guid>
      <description>&lt;p&gt;Quando falamos em comunicação entre sistemas, especialmente no contexto de aplicações distribuídas, estamos lidando com um conjunto de conceitos que muitas vezes ficam escondidos por frameworks e abstrações de alto nível. Entender esses fundamentos ajuda a compreender melhor como APIs, servidores web e integrações realmente funcionam “por baixo dos panos”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protocolos de rede&lt;/strong&gt;&lt;br&gt;
Protocolos de rede são conjuntos de normas e regras que permitem que duas ou mais máquinas conectadas a uma rede se comuniquem entre si. Eles definem como os dados são enviados, em que formato, em que ordem e como erros são tratados.&lt;/p&gt;

&lt;p&gt;Na prática, quando um sistema conversa com outro, não existe “mágica”: existe uma pilha de protocolos, cada um resolvendo um problema específico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O papel do TCP/IP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O TCP (Transmission Control Protocol) é um protocolo da camada de transporte do modelo TCP/IP. Sua principal responsabilidade é garantir que os dados enviados de um ponto cheguem corretamente ao outro.&lt;/p&gt;

&lt;p&gt;O TCP oferece:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comunicação baseada em conexão&lt;/li&gt;
&lt;li&gt;entrega confiável&lt;/li&gt;
&lt;li&gt;Garantia de ordem dos dados&lt;/li&gt;
&lt;li&gt;Retransmissão automática em caso de falhas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por isso, ele é amplamente utilizado em cenários onde integridade e consistência são essenciais, como na comunicação HTTP.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TCP é um protocolo baseado em conexão que fornece um fluxo confiável de dados entre dois computadores.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Protocolo UDP&lt;/strong&gt;&lt;br&gt;
Diferente do TCP, o UDP (User Datagram Protocol) não é baseado em conexão e não garante entrega nem ordem dos dados. Ele envia pacotes independentes, chamados datagramas.&lt;/p&gt;

&lt;p&gt;Essa abordagem faz sentido quando latência é mais importante que confiabilidade e a perda de pacotes não compromete o sistema.&lt;br&gt;
Exemplos: streaming de áudio e vídeo, jogos online, DNS, comando ping.&lt;/p&gt;

&lt;p&gt;Em alguns casos, a confiabilidade do TCP pode até prejudicar o serviço, adicionando sobrecarga desnecessária.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Portas e endereçamento&lt;/strong&gt;&lt;br&gt;
Um computador possui, em geral, uma única conexão física com a rede, mas pode executar vários programas que usam rede simultaneamente. Para isso existem as portas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O IP identifica a máquina&lt;/li&gt;
&lt;li&gt;A porta identifica a aplicação dentro da máquina&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TCP e UDP usam portas para encaminhar os dados ao processo correto.&lt;br&gt;
As portas variam de 0 a 65535, sendo que a porta 0 a 1023 são portas conhecidas (HTTP, HTTPS, FTP etc.) e aplicações customizadas devem usar portas acima desse intervalo.&lt;/p&gt;

&lt;p&gt;Um endpoint é a combinação: IP + porta&lt;/p&gt;

&lt;p&gt;Cada conexão TCP é identificada de forma única pelos dois endpoints (cliente e servidor).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que é um socket&lt;/strong&gt;&lt;br&gt;
Um socket é uma das extremidades de um canal de comunicação bidirecional entre dois programas em execução em uma rede.&lt;/p&gt;

&lt;p&gt;Em Java, o pacote java.net fornece as principais abstrações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Socket → lado do cliente&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ServerSocket → lado do servidor&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando você usa Socket em Java, você já está usando TCP.&lt;br&gt;
O socket não é o protocolo em si, mas a API que permite acessar o TCP.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TCP é o protocolo&lt;br&gt;
Socket é a interface de programação para usá-lo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Socket vs HTTP&lt;/strong&gt;&lt;br&gt;
Ao programar diretamente com sockets, você está trabalhando em um nível mais baixo do que o HTTP.&lt;/p&gt;

&lt;p&gt;O HTTP é um protocolo de aplicação que roda em cima do TCP e usa sockets internamente. Ou seja, HTTP nada mais é do que uma convenção de mensagens (requisição e resposta) que trafegam por um socket TCP.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Como o HTTP funciona por baixo quando um navegador acessa uma página web:&lt;br&gt;
&lt;/u&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O navegador cria um socket TCP&lt;/li&gt;
&lt;li&gt;Conecta-se ao servidor em uma porta específica (ex: 80 ou 443)&lt;/li&gt;
&lt;li&gt;Envia uma requisição HTTP pelo socket&lt;/li&gt;
&lt;li&gt;O servidor recebe bytes brutos&lt;/li&gt;
&lt;li&gt;O servidor interpreta o protocolo HTTP&lt;/li&gt;
&lt;li&gt;O servidor gera uma resposta HTTP e envia a resposta pelo socket&lt;/li&gt;
&lt;li&gt;O navegador recebe, interpreta e renderiza a página&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A conexão pode ser encerrada ou mantida aberta (keep-alive), dependendo da versão do HTTP e dos headers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Programação em rede em Java&lt;/strong&gt;&lt;br&gt;
Muitas pessoas já usam rede em Java sem perceber. Exemplos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Carregar imagens via URL&lt;/li&gt;
&lt;li&gt;Acessar APIs HTTP&lt;/li&gt;
&lt;li&gt;Baixar recursos da internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esses são níveis mais altos de abstração, onde o Java esconde completamente sockets, TCP e detalhes de rede.&lt;/p&gt;

&lt;p&gt;Quando precisamos de mais controle, usamos diretamente Socket e ServerSocket (TCP) OU DatagramSocket e DatagramPacket (UDP).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comunicação cliente-servidor com sockets&lt;/strong&gt;&lt;br&gt;
Em aplicações cliente-servidor o servidor fornece um serviço e o cliente consome esse serviço.&lt;/p&gt;

&lt;p&gt;No modelo TCP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O servidor cria um ServerSocket e fica escutando uma porta&lt;/li&gt;
&lt;li&gt;O cliente cria um Socket e se conecta ao servidor&lt;/li&gt;
&lt;li&gt;O servidor aceita a conexão (accept) e ambos passam a se comunicar lendo e escrevendo no socket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A comunicação acontece por meio de objetos como InputStream, OutputStream ou abstrações como BufferedReader e PrintWriter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Suporte a múltiplos clientes&lt;/strong&gt;&lt;br&gt;
Um servidor real precisa lidar com várias conexões simultâneas.&lt;br&gt;
O padrão básico é:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;while (true) {&lt;br&gt;
    aceitar conexão&lt;br&gt;
    criar uma thread para o cliente&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Cada thread cuida de um socket específico, permitindo que múltiplos clientes sejam atendidos ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protocolo de aplicação&lt;/strong&gt;&lt;br&gt;
Sockets apenas transportam bytes. Para que esses bytes façam sentido, cliente e servidor precisam concordar com um protocolo.&lt;/p&gt;

&lt;p&gt;Usar um protocolo define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Formato das mensagens&lt;/li&gt;
&lt;li&gt;Ordem das interações&lt;/li&gt;
&lt;li&gt;Estados possíveis&lt;/li&gt;
&lt;li&gt;Respostas válidas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E com isso, em sistemas reais o protocolo pode representar comandos, estados, erros, fluxos de negócio.&lt;/p&gt;

&lt;p&gt;Entender TCP, UDP e sockets é entender a base da comunicação entre sistemas. Frameworks como Spring, servidores como Tomcat e protocolos como HTTP existem para facilitar a vida, mas todos eles dependem desses conceitos fundamentais.&lt;/p&gt;

&lt;p&gt;Quando estudamos sockets entendemos o que o HTTP resolve, porquê servidores web existem e como sistemas distribuídos realmente conversam.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Da comunicação via Socket ao Spring Boot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quando começamos a trabalhar com frameworks como Spring Boot, é comum esquecer que, por baixo de tantas abstrações, tudo ainda se resume à troca de bytes pela rede. Entender essa evolução ajuda não só a escrever código melhor, mas também a tomar decisões arquiteturais mais conscientes.&lt;/p&gt;

&lt;p&gt;1- O ponto de partida: TCP e Sockets&lt;br&gt;
Como foi abordado acima, no nível mais baixo que normalmente lidamos em aplicações, temos o TCP (Transmission Control Protocol) que é responsável por garantir que dados cheguem sem perdas e na ordem correta.&lt;/p&gt;

&lt;p&gt;Em Java, a forma mais direta de usar TCP é através de sockets.&lt;/p&gt;

&lt;p&gt;Ao trabalhar diretamente com sockets, o desenvolvedor precisa cuidar de tudo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abrir a conexão&lt;/li&gt;
&lt;li&gt;Ler e escrever bytes&lt;/li&gt;
&lt;li&gt;Definir o formato das mensagens&lt;/li&gt;
&lt;li&gt;Gerenciar múltiplas conexões (threads)&lt;/li&gt;
&lt;li&gt;Tratar falhas e encerramento de conexões&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apesar de poderoso, esse modelo rapidamente se torna difícil de manter. Cada aplicação acaba criando seu próprio “protocolo” e o código fica altamente acoplado à infraestrutura de rede.&lt;/p&gt;

&lt;p&gt;Abaixo um exemplo de representação de um servidor e cliente usando sockets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Server {
  public static void main(String[] args) {
    try(ServerSocket serverSocket = new ServerSocket(4001);
        Socket clientSocket = serverSocket.accept();
        PrintStream out = new PrintStream(clientSocket.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))
    ) {
      String inputLine;
      while((inputLine = reader.readLine()) != null) {
        out.println("Server received: " + inputLine);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Client {

  public static void main(String[] args) {
    try (Socket socket = new Socket("localhost", 4001);
        Scanner scanner = new Scanner(System.in);
        PrintStream out = new PrintStream(socket.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))
    ) {
      String message = scanner.nextLine();

      out.println(message); // envia para o servidor

      String response = reader.readLine(); // lê resposta do servidor
      System.out.println("Resposta do servidor: " + response);

    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2- HTTP: padronizando a comunicação&lt;br&gt;
Para resolver a falta de padronização, surge o HTTP. O HTTP é um protocolo de aplicação que roda sobre o TCP e define regras claras para comunicação:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Métodos (GET, POST, PUT, PATCH, DELETE)&lt;/li&gt;
&lt;li&gt;Cabeçalhos&lt;/li&gt;
&lt;li&gt;Códigos de status&lt;/li&gt;
&lt;li&gt;Formato de requisição e resposta&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com isso, clientes e servidores passam a “falar a mesma língua”, navegadores se tornam possíveis e APIs começam a surgir de forma consistente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: HTTP não substitui o socket, ele apenas organiza o que é transmitido por ele.&lt;/p&gt;

&lt;p&gt;3- Servlet API: a entrada do Java no mundo Web&lt;br&gt;
Para padronizar aplicações web em Java, surge a Servlet API com o intuito de abstrair o HTTP em objetos Java.&lt;/p&gt;

&lt;p&gt;Assim, o desenvolvedor passa a trabalhar com HttpServletRequest, HttpServletResponse e métodos como doGet e doPost.&lt;/p&gt;

&lt;p&gt;Com isso, não é mais necessário abrir sockets manualmente, interpretar requisições HTTP “na unha”, lidar diretamente com concorrência de conexões...O foco passa a ser a requisição HTTP, não a rede.&lt;/p&gt;

&lt;p&gt;4- Servlet Containers: onde o Tomcat entra&lt;/p&gt;

&lt;p&gt;Alguém ainda precisa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Escutar portas&lt;/li&gt;
&lt;li&gt;Gerenciar threads&lt;/li&gt;
&lt;li&gt;Implementar a Servlet API&lt;/li&gt;
&lt;li&gt;Controlar o ciclo de vida da aplicação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse é o papel dos Servlet Containers, como Tomcat, Jetty, Undertow.&lt;/p&gt;

&lt;p&gt;O Tomcat, por exemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abre sockets TCP&lt;/li&gt;
&lt;li&gt;Processa HTTP&lt;/li&gt;
&lt;li&gt;Instancia servlets&lt;/li&gt;
&lt;li&gt;Delega a execução para o código da aplicação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5- Web Servers: lidando com conexões em escala&lt;br&gt;
Enquanto a evolução do desenvolvimento Java na Web passa por Socket → Servlet → Spring, os Web Servers surgem como uma resposta a problemas de infraestrutura: escala, segurança e performance. Eles não substituem a aplicação Java nem o container de servlets, mas atuam como uma camada intermediária entre a internet e o Tomcat.&lt;/p&gt;

&lt;p&gt;Eles ficam responsáveis principalmente por:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encerrar conexões TCP e TLS&lt;/li&gt;
&lt;li&gt;Atuar como reverse proxy&lt;/li&gt;
&lt;li&gt;Servir conteúdo estático com alta performance&lt;/li&gt;
&lt;li&gt;Proteger e aliviar carga do container de aplicação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Porém, esses servidores não resolvem a lógica de negócio da aplicação. Eles cuidam da infraestrutura, não do domínio.&lt;/p&gt;

&lt;p&gt;6- As primeiras abstrações Web em Java&lt;/p&gt;

&lt;p&gt;Com o tempo, escrever HTML dentro de servlets se mostrou pouco produtivo. Surgiram então tecnologias como JSP e JSF que ajudaram a separar melhor a camada de visualização, mas também introduziram complexidade, acoplamento e dificuldade de manutenção.&lt;br&gt;
Essas limitações abriram espaço para soluções mais modernas.&lt;/p&gt;

&lt;p&gt;7- Spring Framework: desacoplamento e organização&lt;/p&gt;

&lt;p&gt;O Spring nasce para resolver problemas estruturais do desenvolvimento Java:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alto acoplamento&lt;/li&gt;
&lt;li&gt;Dificuldade de testes&lt;/li&gt;
&lt;li&gt;Dependências rígidas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No contexto web, com o Spring MVC, o desenvolvedor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não precisa estender HttpServlet&lt;/li&gt;
&lt;li&gt;Trabalha com controllers&lt;/li&gt;
&lt;li&gt;Define rotas por anotações&lt;/li&gt;
&lt;li&gt;Separa claramente responsabilidades&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Spring continua rodando sobre Servlet API e Tomcat (ou outro container), mas abstrai quase completamente esses detalhes.&lt;/p&gt;

&lt;p&gt;8- Spring Boot: produtividade máxima&lt;/p&gt;

&lt;p&gt;Mesmo com Spring, a configuração ainda era extensa. O Spring Boot surge para simplificar tudo isso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-configuration&lt;/li&gt;
&lt;li&gt;Servidor embutido&lt;/li&gt;
&lt;li&gt;Inicialização simples&lt;/li&gt;
&lt;li&gt;Menos boilerplate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hoje, basta:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;java -jar app.jar&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;E a aplicação está rodando e com Tomcat incluso, mesmo que o desenvolvedor nem perceba.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusão&lt;/strong&gt;&lt;br&gt;
A evolução das aplicações web em Java pode ser vista como uma sequência de abstrações, cada uma resolvendo um problema específico:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evolução da comunicação e programação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;TCP → Socket → HTTP → Servlet API → Spring → Spring Boot&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evolução da infraestrutura&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Web Servers (Apache/Nginx) → Servlet Containers (Tomcat/Jetty)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Cada camada reduz complexidade, aumenta produtividade e afasta o desenvolvedor dos detalhes de baixo nível, mas entender o que existe por baixo dessas abstrações é o que diferencia quem apenas usa frameworks de quem arquitetura sistemas.&lt;/p&gt;

&lt;p&gt;No fim das contas, toda requisição HTTP ainda começa e termina em um socket TCP, mesmo quando estamos usando Spring Boot.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>java</category>
      <category>programming</category>
      <category>springboot</category>
    </item>
    <item>
      <title>O que é e Quais os Tipos de Acoplamento - Existe Acoplamento "Bom"?</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Tue, 31 Oct 2023 20:09:51 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/o-que-e-e-quais-os-tipos-de-acoplamento-existe-acoplamento-bom-1f0f</link>
      <guid>https://forem.com/jeronimafloriano/o-que-e-e-quais-os-tipos-de-acoplamento-existe-acoplamento-bom-1f0f</guid>
      <description>&lt;p&gt;Segundo o dicionário, uma definição da palavra acoplamento é:&lt;/p&gt;

&lt;p&gt;1.união ou ligação entre dois ou mais corpos, formando um único conjunto.&lt;br&gt;
2.conexão, compatibilização (de fatos, ações etc.).&lt;/p&gt;

&lt;p&gt;No contexto de software, consideramos acoplamento a dependência entre classes, que tem tudo a ver com a definição da palavra em si. Quando uma classe "chama" outra para executar algo ou buscar algum dado/valor, em qualquer ponto, podemos dizer que existe ali um acoplamento, pois ela depende de alguma coisa que essa outra classe que está sendo chamada faz ou possui.&lt;br&gt;
Ao usar qualquer biblioteca estamos gerando um acoplamento, mesmo em bibliotecas "core" de cada linguagem.&lt;/p&gt;

&lt;p&gt;Quando implementamos um sistema, naturalmente queremos evitar o máximo possível de falhas que possam ocorrer ou fatores externos que possam impactar esse sistema de alguma forma. &lt;br&gt;
É aí que começamos a discutir sobre acoplamento. Quando dependemos de outras classes, sejam abstrações ou implementações concretas, estamos sujeitos as alterações que essas classes podem fazer.&lt;/p&gt;

&lt;p&gt;Até aí tudo bem, pois é quase impossível criarmos classes que não dependem de nenhuma outra. Se esse fosse o objetivo, tudo que fossemos criar teríamos que implementar do zero, "reinventar a roda" toda vez, e sabemos que isso vai contra o reuso de código. &lt;/p&gt;

&lt;p&gt;Além do mais, uma classe da qual dependemos alterar internamente uma implementação não é necessariamente algo ruim, pois se criamos um sistema coeso não importa como outras classes implementam seus métodos, contanto que façam o que tem que fazer corretamente.&lt;/p&gt;

&lt;p&gt;Por isso podemos dizer que existem dois tipos de acoplamento: o acoplamento bom(ou aceitável) e o acoplamento ruim. Para entendê-los, precisamos antes entender outros dois conceitos de acoplamento: Acoplamento Evolutivo e Acoplamento Estrutural.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acoplamento Evolutivo:
O acoplamento evolutivo em software ocorre quando duas partes do código estão tão interligadas que mudanças em uma parte podem forçar mudanças na outra parte para manter a compatibilidade. Em outras palavras, se você altera uma parte do sistema, é necessário fazer alterações em outra parte do sistema para que ele continue funcionando corretamente.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
Exemplo de Acoplamento Evolutivo:
Imagine um sistema para um site de comércio eletrônico. Temos uma classe Pedido e uma classe Produto. A classe Produto, grava o preço de um produto acessando uma planilha do Excel e registrando o valor na coluna PRECO. Já a classe Pedido tem um método para calcular o valor total de um pedido somando o preço de cada produto no pedido, e para buscar o valor do preço do produto ela lê essa planilha do Excel buscando a coluna PRECO para fazer o somatório.

Nesse caso temos um acoplamento evolutivo, pois uma simples mudança no formato do arquivo gravado na classe Produto teria impacto na classe Pedido.
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;Acoplamento Estrutural:
O acoplamento estrutural se refere à dependência entre os componentes do sistema: Uma classe A possui uma referência explícita em seu código para uma classe B. 
Por exemplo, no sistema de comércio eletrônico citado anteriormente, cada pedido teria que ter uma lista de produtos. Então na classe Pedido suponhamos que essa lista estivesse armazenada em uma variável:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List&amp;lt;Produto&amp;gt; produtos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
Nesse caso, temos um acoplamento estrutural entre Pedido e List.
&lt;/ul&gt;

&lt;p&gt;Tendo isso em mente, podemos observar que o acoplamento menos prejudicial tende a ser o estrutural, onde as mudanças não se propagam tão diretamente. Além disso, um acoplamento  pode ser considerado mais aceitável quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependemos de interfaces e não de implementações. Ao dependermos de uma interface não estamos sujeitos a detalhes das implementações, podendo trocar a implementação facilmente sem alterar nossas classes. &lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
Por exemplo: Uma classe que realiza um processo X e chama uma outra para fazer o envio de uma mensagem no final desse processo, que pode ser via chat, email ou etc. O ideal seria termos uma interface do tipo Mensagem e ao realizar o envio da mensagem não teríamos que nos preocupar qual vai ser o tipo de implementação dessa interface(ou seja, como a mensagem será enviada), se via chat ou email.
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;As interfaces que dependemos são estáveis, ou seja, as assinaturas dos métodos não mudam com frequência.&lt;/li&gt;
&lt;li&gt;Dependemos apenas de métodos públicos das outras classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um acoplamento pode ser considerado ruim e de má prática, quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependemos de classes instáveis, que são alteradas com frequência.&lt;/li&gt;
&lt;li&gt;Acessamos diretamente detalhes da implementação de uma classe que dependemos, por exemplo acessar diretamente arquivos, banco de dados, atributos etc. Se essa classe que dependemos mudar um tipo de arquivo ou o tipo de banco de dados, quebraríamos nossa aplicação.&lt;/li&gt;
&lt;li&gt;Os métodos dos quais dependemos são confusos e não deixam claro o que fazem.&lt;/li&gt;
&lt;li&gt;As classes compartilham variáveis ou dados globais com as classes dependentes, por exemplo, a classe B altera o valor de uma variável global que a classe A usa no seu código.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mesmo seguindo essas "boas práticas" de acoplamento, é importante evitarmos estar acoplados a muitas interfaces diferentes, pois isso naturalmente aumenta o impacto dessas dependências em nossa aplicação. Aliás, muitas dependências podem ser um indicativo de que nossa classe possa estar pouco coerente, realizando muitas funções que poderiam ser de responsabilidade de outras classes.&lt;/p&gt;

&lt;p&gt;Além disso, existe também o acoplamento indireto. Podemos estar dependendo de classes que dependem de outras classes e assim sucessivamente. Se uma classe A depende da B que depende da C, e C por algum motivo gera um comportamento inesperado que afeta a classe B, consequentemente a classe A também pode ser impactada.&lt;/p&gt;

&lt;p&gt;Resumindo, acoplamento não é necessariamente algo ruim. Entender e gerenciar os tipos de acoplamento evolutivo e estrutural é essencial para o desenvolvimento de software robusto e flexível. Ao aderir às boas práticas, como depender de interfaces estáveis e evitar acessos diretos a implementações específicas, podemos minimizar o impacto das mudanças e promover sistemas mais coesos e de fácil manutenção, garantindo assim a qualidade e a adaptabilidade das nossas aplicações.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Referências: Livro Engenharia de Software Moderna, do Marco Tulio Valente, capítulo 5.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>braziliandevs</category>
      <category>solidprinciples</category>
      <category>softwaredevelopment</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Princípios SOLID</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Wed, 25 Oct 2023 13:56:10 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/principios-solid-3pj1</link>
      <guid>https://forem.com/jeronimafloriano/principios-solid-3pj1</guid>
      <description>&lt;p&gt;SOLID é um acrônimo que representa cinco princípios de design de software que visam criar código mais compreensível, flexível e fácil de manter.&lt;/p&gt;

&lt;p&gt;Esses princípios se baseiam nos paradigmas de coesão, encapsulamento e acoplamento da orientação a objetos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Coesão: A classe só tem atributos/responsabilidades que estejam relacionadas à ela. Uma classe "Funcionário" só vai ter informações referentes ao funcionário, uma única responsabilidade.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encapsulamento: Proteger uma classe contra manipulações externas. Por exemplo, fazer validações nos métodos da classe, que irão protegê-la de fazer alterações indevidas e violações da regra de negócio do sistema. Para fora da classe, devemos fornecer acesso apenas ao que é necessário em nossas classes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Acoplamento: Uma classe utilizar outra, a dependência entre classes. A própria classe deve implementar os métodos que necessitam chamar outras classes/métodos, isso não deve ser manual de fora da classe.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com esses princípios esclarecidos, vamos entender as letras do acrônimo SOLID:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;S - Single Responsibility Principle&lt;/u&gt;&lt;br&gt;
"Uma classe deveria ter apenas um único motivo para mudar." Robert Martin&lt;/p&gt;

&lt;p&gt;O Princípio da Responsabilidade Única (SRP) está relacionado às responsabilidades de uma classe e está muito ligado à coesão. Coesão significa coerência de pensamento ou de um todo. &lt;br&gt;
No exemplo da classe “Funcionário”, vamos pensar no salário do funcionário. Salário é algo que todo funcionário tem, mas é uma responsabilidade do funcionário gerenciar o salário? Essa responsabilidade está mais atrelada ao domínio que cuida de salários, por exemplo, Folha de Pagamento ou RH. O funcionário apenas possui um salário atrelado à ele, mas não é responsabilidade dele gerenciar esse salário. &lt;br&gt;
Vamos pensar por exemplo se surgir uma alteração nos impostos debitados de um salário, ou no fechamento do mês quando fosse contabilizado os dias trabalhados, ou ainda nos períodos de férias…Cada vez que isso acontecesse teríamos que alterar a classe Funcionario. Também teríamos que alterá-la quando um funcionário mudasse de endereço, incluísse novos dependentes etc. Seriam muitas responsabilidades diferentes em uma classe só, o que leva à perda de coesão. &lt;/p&gt;

&lt;p&gt;Portanto, o princípio da responsabilidade única se baseia na definição de responsabilidades. É necessário conhecer bem o negócio e o domínio da aplicação para separarmos as responsabilidades de cada domínio. &lt;/p&gt;

&lt;p&gt;Para analisarmos se uma classe atende ao SRP, precisamos responder a duas perguntas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Quais as responsabilidades dessa classe?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quais os motivos para essa classe ser modificada?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se a classe possui muitos métodos diferentes, é modificada com frequência, não para de crescer e depende de muitas classes que não tem uma relação que faça sentido,  é provável que tenhamos uma classe com muitas responsabilidades diferentes.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;O - Open Closed Principle(OCP)&lt;/u&gt;&lt;br&gt;
Classes devem estar abertas para extensão, mas fechadas para modificação. Ou seja, é  recomendável evitar ficar alterando o código que já existe e ao invés disso adicionar os novos comportamentos quando necessário. Então, sempre que uma nova funcionalidade for implementada, o ideal é que possamos criar código novo e editar o mínimo possível de código já existente, pois ao editar código existente podemos acabar quebrando funcionalidades já implementadas e funcionais. &lt;br&gt;
Para isso acontecer, devemos garantir que cada ação/responsabilidade esteja na classe correta, pois quando muitos comportamentos diferentes são agrupados em uma única classe, é difícil não modificar o que já existe, e com isso podemos acabar usando muitas declarações condicionais para selecionar o comportamento correto. Encapsular o comportamento em classes de estratégia separadas pode ser uma estratégia para eliminar essas declarações condicionais. Um bom design OO vai ter poucas condicionais como if-else ou switch-case. &lt;/p&gt;

&lt;p&gt;&lt;u&gt;L - Liskov Substitution  Principle (LSP) &lt;/u&gt;&lt;br&gt;
O Princípio de Substituição de Liskov é  o princípio da substituibilidade. Ele define que subtipos devem ser substituíveis por seus tipos base. Quando usamos herança do jeito certo, deve ser possível usar qualquer método das classes filhas ao recebermos uma variável cujo tipo é o da classe mãe. &lt;br&gt;
Por exemplo, se temos uma classe Cachorro que estende de Animal, qualquer comportamento de cachorro deve poder ser substituído pelo tipo Animal. Em um subtipo podemos fazer mais coisas que a classe mãe e até alterar alguns comportamentos, mas não podemos fazer nada a menos.&lt;/p&gt;

&lt;p&gt;Entretanto, devemos verificar a real necessidade de usar a herança, pois ela pode muitas vezes levar à intimidade excessiva. O uso de herança faz com que a classe filha tenha um forte acoplamento (ou intimidade) com sua classe mãe, e as subclasses sempre saberão mais sobre seus pais do que esses gostariam que elas soubessem. Por isso, é preferível usar a composição. &lt;br&gt;
No exemplo da classe Funcionário e Salário, todo funcionário possui um salário mas não deve ser de responsabilidade do funcionário gerenciar o salário. Podemos então ter uma referência de um objeto Salário na classe Funcionário, como atributo privado. O Funcionário então possui um Salário atrelado a ele, e qualquer mudança na classe Salário será feita diretamente nela, e o Funcionário poderá usufruir dos seus métodos públicos.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;I - Interface Segregation Principle (ISP)&lt;br&gt;&lt;br&gt;
&lt;/u&gt;O princípio da segregação de interface prega que devemos depender de interfaces e não de implementações. Devemos possuir interfaces coesas, cujos comportamentos são simples e bem definidos, pois classes que dependem de interfaces leves sofrem menos com mudanças em outros pontos do sistema.&lt;/p&gt;

&lt;p&gt;Vamos considerar um cenário em que estamos trabalhando com dispositivos eletrônicos que podem ser ligados e desligados remotamente. Podemos criar interfaces segregadas para garantir que os dispositivos só precisem implementar os métodos relevantes para suas funcionalidades. Neste exemplo, teríamos a interface DispositivoLigavel e as classes Lampada e Televisao implementariam essa interface, cada uma delas representando um tipo diferente de dispositivo.&lt;br&gt;
A classe ControleRemoto recebe qualquer dispositivo que implemente a interface DispositivoLigavel. Isso ilustra o princípio da segregação de interface, pois as implementações de Lampada e Televisao podem ser usadas de forma polimórfica através da interface comum DispositivoLigavel. Dessa forma, o código do controle remoto não precisa se preocupar com os detalhes específicos de cada dispositivo, apenas com os métodos definidos na interface, garantindo assim a aplicação do ISP.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;D - Dependency Inversion&lt;/u&gt; &lt;br&gt;
O Princípio da Inversão de Dependência estabelece que módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações. &lt;br&gt;
Além disso, abstrações não devem depender de detalhes. Em vez disso, os detalhes devem depender das abstrações. &lt;br&gt;
Com isso, uma classe não deve ser obrigada a implementar métodos de determinada interface que não fazem sentido para ela. Em outras palavras, o DIP sugere que as dependências de um sistema devem ser invertidas, tornando o sistema mais flexível, modular e fácil de manter.&lt;/p&gt;

&lt;p&gt;Por exemplo, suponha que estamos construindo um sistema de notificação onde temos uma classe Notificador que é responsável por enviar mensagens. Inicialmente, poderíamos implementar a classe Notificador para enviar e-mails, criando uma dependência direta entre o módulo de alto nível (que usa a classe Notificador) e o módulo de baixo nível (a implementação do e-mail).&lt;br&gt;
Neste exemplo, a classe SistemaDePedido teria uma dependência direta da implementação de e-mail da classe Notificador. Isso viola o DIP porque o módulo de alto nível (SistemaDePedido) está diretamente ligado ao módulo de baixo nível (Notificador).&lt;br&gt;
Para aplicar o DIP, podemos introduzir uma abstração, como uma interface MeioDeComunicacao, que define um método enviarMensagem. Em seguida, tanto Notificador quanto SistemaDePedido dependem da abstração em vez de dependerem diretamente um do outro.&lt;br&gt;
Assim, Notificador implementaria a interface MeioDeComunicacao, garantindo que ambas as classes dependam da abstração em vez de dependerem diretamente uma da outra. Isso torna o sistema mais flexível, pois podemos introduzir diferentes meios de comunicação (como SMS, notificações push, etc.) sem modificar o SistemaDePedido, desde que eles implementem a interface MeioDeComunicacao.&lt;br&gt;
Assim, o Princípio da Inversão de Dependência (DIP) ajuda a reduzir o acoplamento entre os módulos, tornando o sistema mais modular, fácil de manter e extensível.&lt;/p&gt;

&lt;p&gt;Os princípios SOLID são amplamente usados por desenvolvedores de software para criar sistemas mais robustos, flexíveis e fáceis de manter. Seguir os princípios SOLID ajuda a melhorar a qualidade do código, facilita a manutenção e favorece a extensibilidade do software.&lt;/p&gt;

&lt;p&gt;Referências: Livro "Desbravando SOLID -Práticas avançadas para códigos de qualidade em Java moderno" do Alexandre Aquiles.&lt;/p&gt;

</description>
      <category>java</category>
      <category>braziliandevs</category>
      <category>softwaredevelopment</category>
      <category>solidprinciples</category>
    </item>
    <item>
      <title>O que são Requisitos de Software e Porquê é Importante Entendê-los</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Tue, 26 Sep 2023 13:26:40 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/o-que-sao-requisitos-de-software-e-porque-e-importante-entende-los-bjn</link>
      <guid>https://forem.com/jeronimafloriano/o-que-sao-requisitos-de-software-e-porque-e-importante-entende-los-bjn</guid>
      <description>&lt;p&gt;Requisitos de software são as descrições de serviços, funcionalidades e restrições que um sistema deve oferecer. O levantamento de requisitos de um sistema é feito nas etapas iniciais de um projeto de software, antes da concepção do produto em si. É no levantamento que elucidamos junto aos clientes e usuários do sistema quais são as necessidades da aplicação, portanto, é crucial que todos os envolvidos estejam alinhados sobre essas necessidades e que os requisitos estejam bem escritos e de fácil entendimento.&lt;/p&gt;

&lt;p&gt;Entretanto, escrever bons requisitos é algo complexo. As necessidades dos clientes mudam a todo momento, em parte porque vivemos em um mundo por si só instável e em constante mudança. Além disso, em muitas empresas não temos apenas um desenvolvedor responsável pelo sistema, e sim toda uma equipe, e cada pessoa pode ter um entendimento diferente de algo que foi solicitado pelo usuário. E mais, muitas vezes o próprio cliente não tem certeza sobre o que ele precisa! &lt;/p&gt;

&lt;p&gt;Pensando pelo lado do desenvolvedor de software, caso trabalhar em time ágil o desenvolvedor não será apenas a pessoa que escreve código, ele também irá participar de outras etapas do ciclo de vida do software, podendo realizar suas contribuições. E mesmo que não participe, também cabe à ele ter um olhar crítico ao receber uma tarefa para ser desenvolvida, não apenas fazendo o que está escrito, mas avaliando se de fato aquilo faz sentido e agrega valor. Além disso, caso os requisitos não sejam atendidos de forma satisfatória, irá gerar um retrabalho ao desenvolvedor posteriormente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vZA7lk_u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oefea58tdq7hvy2bissd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vZA7lk_u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oefea58tdq7hvy2bissd.png" alt="Image description" width="646" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por isso, existem as técnicas e processos de modelagem dos sistemas e criação de requisitos que nos auxiliam no entendimento do problema, na avaliação dos riscos e definição da solução, de uma maneira que seja mais fácil unir todas as informações necessárias e com maior precisão.&lt;/p&gt;

&lt;p&gt;O processo de escrita de requisitos pode envolver várias etapas, sendo as principais: Levantamento, Registro, Validação e Verificação. A forma que será implementado depende da empresa e das necessidades do sistema. &lt;br&gt;
De forma resumida, temos dois tipos principais de requisitos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requisitos de usuário&lt;/strong&gt;:&lt;br&gt;
São declarações em linguagem natural com diagramas, de quais serviços são esperados do sistema e as restrições sob as quais ele deve operar, escritos para serem lidos por qualquer usuário. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requisitos de sistema&lt;/strong&gt;: &lt;br&gt;
Definem as funções, os serviços e as restrições operacionais do sistema, de forma precisa e pontuando exatamente o que será implementado, e são escritos para serem lidos por usuários finais, arquitetos de sistemas e desenvolvedores.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplo de requisito de usuário e de sistema de biblioteca:&lt;br&gt;
&lt;u&gt;Requisito de usuário&lt;/u&gt;&lt;br&gt;
O usuário irá acessar o acervo da biblioteca e realizar a busca de livros, com base em diferentes critérios de pesquisa.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Requisitos de sistema&lt;/u&gt;&lt;br&gt;
1 - O sistema deve permitir que os usuários filtrem sua busca por título do livro, categoria, data de publicação, autor e disponibilidade.&lt;br&gt;
2 - Após a pesquisa, serão exibidos os resultados apresentando as informações resumidas de título, autor, categoria e disponibilidade. &lt;br&gt;
3 - O sistema deverá possuir a opção de ordenação dos resultados de pesquisa por ordem alfabética, publicação mais recente e publicação mais antiga.&lt;/p&gt;

&lt;p&gt;Os requisitos(de usuário ou de sistema) também podem ser classificados em requisitos funcionais, requisitos não funcionais e requisitos de domínio.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requisitos funcionais&lt;/strong&gt;:
São declarações das funcionalidades do sistema e de serviços que o sistema deve fornecer, como o sistema deve reagir a entradas específicas e como o sistema deve se comportar em determinadas situações. Também podem estabelecer explicitamente o que o sistema não deve fazer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O exemplo de requisitos de usuário e de sistema de biblioteca mencionado anteriormente, se tratam de requisitos funcionais.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requisitos não funcionais&lt;/strong&gt;:
São restrições sobre os serviços ou as funções oferecidos pelo sistema.
Normalmente, aplicam-se ao sistema como um todo e incluem restrições de timing, restrições sobre o processo de desenvolvimento e padrões, restrições técnicas, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplo de requisito não funcional do sistema de biblioteca:&lt;/p&gt;

&lt;p&gt;Ao realizar a pesquisa por títulos na biblioteca, o tempo de resposta da consulta não deve exceder 3 segundos em condições normais de uso.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requisitos de domínio&lt;/strong&gt;
São provenientes do domínio da aplicação, refletem as características e as restrições desse domínio. Podemos pensar como aquilo que é comum a todos os sistemas daquele nicho. No caso de uma biblioteca, um requisito de domínio poderia se referir ao empréstimo de livros, algo que é comum a toda biblioteca.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tipos de escrita de requisitos&lt;/strong&gt;&lt;br&gt;
A escrita de requisitos pode ser abordada de várias maneiras, dependendo das necessidades do projeto e das metodologias utilizadas. &lt;br&gt;
Na abordagem descritiva ou tradicional por exemplo, os requisitos são documentados em detalhes antes do início do desenvolvimento. Isso inclui documentos extensos, como especificações de requisitos de software que descrevem o que o sistema deve fazer em termos claros e específicos.&lt;/p&gt;

&lt;p&gt;Já na abordagem ágil, os requisitos são frequentemente escritos de forma mais leve e flexível, geralmente sendo escritos em forma de histórias de usuário, que são declarações simples e informais de necessidades do cliente. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Técnicas de Levantamento de Requisitos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seja qual for a abordagem de escrita de requisitos, diversas técnicas podem ser utilizadas no levantamento de requisitos para que seja mais simples entender e visualizar o sistema antes de ser totalmente desenvolvido.&lt;/p&gt;

&lt;p&gt;Alguns exemplos de técnicas: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Entrevistas&lt;/strong&gt;: Consiste em conversas direcionadas com os clientes/usuários com um propósito específico e com formato “pergunta-resposta”, com o objetivo de descobrir problemas a serem tratados, levantar procedimentos importantes e saber a opinião e as expectativas do entrevistado sobre o sistema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Questionários&lt;/strong&gt;: Utilizar questionários direcionados aos futuros usuários para obter informações sobre os mesmos e sobre o sistema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observação&lt;/strong&gt;: Consiste em observar o comportamento e o ambiente dos indivíduos de vários níveis organizacionais. Por exemplo, em um sistema de biblioteca poderia ser útil observar os bibliotecários ou os clientes de uma biblioteca física, além dos gestores, para capturarmos o que realmente é feito no dia a dia deles e qual tipo de suporte computacional é necessário. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Análise de documentos&lt;/strong&gt;: pela análise de documentos existentes na organização, podemos obter informações e detalhes difíceis de conseguir por entrevista e observação. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cenários&lt;/strong&gt;: Montar cenários de interação entre o usuário final e o sistema,  simulando a interação entre eles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prototipagem&lt;/strong&gt;: Criar uma versão preliminar do sistema, muitas vezes não operacional e descartável, que é apresentada ao usuário para observar reações iniciais e obter sugestões.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dinâmicas de Grupo&lt;/strong&gt;: Podem ser utilizadas diversas técnicas que exploram dinâmicas de grupo para a descoberta e o desenvolvimento de requisitos, como por exemplo o Brainstorming, que reúne representantes de diferentes grupos de interessados para gerar o maior número possível de ideias. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uma vez identificados e negociados, a documentação dos requisitos (seja na abordagem tradicional onde são criados os documentos de requisitos ou na criação das histórias de usuários na abordagem ágil) é útil ao desenvolvermos o sistema, ao testarmos e ao gerarmos a documentação das funcionalidades. Além disso, também pode servir de base e registro para mudanças que são realizadas ao longo do tempo, auxiliando no preparo e planejamento dessas mudanças. &lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Classes Imutáveis no Java e Records</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Sun, 03 Sep 2023 23:10:30 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/classes-imutaveis-no-java-e-records-2ibm</link>
      <guid>https://forem.com/jeronimafloriano/classes-imutaveis-no-java-e-records-2ibm</guid>
      <description>&lt;p&gt;Classes imutáveis são aquelas cujas instâncias não podem ser modificadas durante toda a vida útil do objeto, como por exemplo a classe String.&lt;/p&gt;

&lt;p&gt;Ter um objeto imutável garante que seu valor não será modificado em nenhum lugar do sistema. Isso evita erros e problemas de concorrência que podem ocorrer quando vários threads tentam modificar o mesmo objeto ao mesmo tempo, por exemplo. Ou seja, uma classe imutável é naturalmente thread-safe. Além disso, esses objetos também podem ser armazenados em cache com segurança, pois não mudarão.&lt;/p&gt;

&lt;p&gt;Para desenvolver uma classe imutável , até o java 16, é necessário:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar a classe como "final", para garantir  que ela não possa ser estendida, evitando que sub classes tenham acesso aos seus dados;&lt;/li&gt;
&lt;li&gt;Todos os campos devem ser declarados como finais e privados;&lt;/li&gt;
&lt;li&gt;Os atributos devem ser iniciados no construtor da classe;&lt;/li&gt;
&lt;li&gt;Não fornecer métodos que modifiquem o estado do objeto(setters);
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public final class Pessoa{

    private final String nome;
    private final int idade;

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

    public String getNome() {
        return this.nome;
    }

    public int getIdade() {
        return this.idade;
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir do Java versão 16, é possível utilizar os records para essa finalidade. &lt;/p&gt;

&lt;p&gt;Um Record é um tipo de classe que armazena dados, similar a um Java Bean e que já é imutável por padrão. Ela estende implicitamente de Record, e também são implicitamente final. &lt;br&gt;
Essas classes ao serem criadas, já possuem os métodos equals, hashCode e toString() além de um método assessor para cada atributo, com o mesmo nome do atributo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public record Pessoa(String nome, int idade) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basta definir na declaração da classe os seus componentes(que neste exemplo são String nome e int idade) e você já "ganha" os metodos: nome(), idade(), equals, hashCode e toString().&lt;/p&gt;

&lt;p&gt;Portanto, com apenas algumas linhas de código você pode criar uma classe de dados imutável. Isso pode ser muito útil quando precisamos representar objetos simples e garantir que seu estado não será alterado.&lt;/p&gt;

&lt;p&gt;Observação: Records em Java, assim como as classes final, fornecem imutabilidade apenas para seus próprios componentes (atributos). Se uma classe record tiver referências a objetos mutáveis como componentes, esses objetos em si não se tornarão automaticamente imutáveis por estarem contidos em um record. &lt;br&gt;
Exemplo: Um record "Pessoa" que tem um atributo que referencia a um objeto "Endereço" mutável. Neste caso, a instância de Pessoa em si é imutável, ou seja, você não pode alterar seus atributos depois que o objeto Pessoa é criado. No entanto, o "Endereço" ainda é mutável, o que significa que você pode modificar o endereço após a criação do objeto Pessoa. Exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Endereco endereco = new Endereco("Brasil", "Sao Paulo");
Pessoa pessoa = new Pessoa("Maria", endereco);
pessoa.getEndereco().setEstado("XXX"); 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso não é impedido pelo record, nem pelas classes final. Portanto, para garantir a imutabilidade certifique-se de que objetos imutáveis não estejam vinculados à objetos mutáveis ou ofereça cópias defensivas de quaisquer vínculos à objetos mutáveis.&lt;/p&gt;

</description>
      <category>java</category>
      <category>backend</category>
      <category>backenddevelopment</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Programação Orientada à Objetos com Java - POO</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Sun, 27 Aug 2023 14:26:39 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/programacao-orientada-a-objetos-com-java-poo-1np2</link>
      <guid>https://forem.com/jeronimafloriano/programacao-orientada-a-objetos-com-java-poo-1np2</guid>
      <description>&lt;p&gt;POO é um paradigma de programação onde tudo é representado como um objeto. Um programa feito sobre esse paradigma é então composto por uma série de objetos que passam mensagens uns para os outros. Eventualmente, essa troca de mensagens produzirá modificações de estado (dados) nestes objetos.&lt;/p&gt;

&lt;p&gt;Os objetos possuem características(atributos) e comportamentos(métodos). Cada objeto deriva de uma classe, que são abstrações de objetos do mundo real. Uma classe é um template, como a "planta" de uma construção, a partir do qual os objetos são criados.&lt;/p&gt;

&lt;p&gt;Enquanto a lógica procedural tem analogia comum com “receitas de bolo”, descrevendo apenas “como” as coisas precisam ser feitas, a lógica orientada a objetos inclui “quem”, ou seja, os atores (que desempenham as ações) e os alvos .&lt;/p&gt;

&lt;p&gt;Em linguagens procedurais, comportamentos são definidos em procedimentos, funções ou subrotinas. Em programas OO, os diversos comportamentos de um objeto são métodos. Os métodos de um objeto são “invocados” através de mensagens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;É alocado espaço na memória sempre que um objeto lógico é criado. Classes não consomem espaço na memória..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ao programar orientado à objetos, temos os benefícios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Código mais fácil de compreender, pois o código é estruturado de maneira que simbolizam elementos do mundo real, &lt;/li&gt;
&lt;li&gt;Mais fácil de dar manutenção (manutenibilidade), pois as responsabilidades estão direcionadas aos objetos&lt;/li&gt;
&lt;li&gt;Reutilização de código: A herança, um dos pilares da POO, permite que os objetos herdem características e comportamentos, evitando a repetição de código.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Os pilares que regem a programação orientada à objetos são: Encapsulamento, Herança, Polimorfismo e Abstração.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variável de referência&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Podemos acessar um objeto através de uma variável de referência. Uma variável de referência pode ser apenas de um tipo. Após declarada, o tipo da variável de referência não pode ser alterado. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cachorro cachorro = new Cachorro();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;No exemplo acima, cachorro é a variável de referência a um objeto do tipo Cachorro(a classe). Uma variável de referência pode ter uma classe ou uma interface como tipo.&lt;/p&gt;

&lt;p&gt;Um único objeto pode ser referenciado por variáveis de referência de diversos tipos (desde que esses tipos estejam na mesma hierarquia), sendo o objeto do mesmo tipo da variável de referência ou de uma superclasse.&lt;/p&gt;

&lt;p&gt;Por exemplo, se a classe Cachorro estende da classe Animal, poderíamos dizer:&lt;br&gt;
&lt;code&gt;Animal rex = new Cachorro();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso, rex seria uma variável de referência do tipo Animal e new Cachorro() criará um novo objeto do tipo Cachorro. Em tempo de compilação, não poderíamos acessar um método ou atributo específico de Cachorro, como por exemplo o método "latir()", porque o compilador conhece apenas o tipo de referência.  Já que latir() não existe na classe do tipo de referência Animal (Só existe na classe Cachorro), não é possível acessá-lo. Em tempo de execução, no entanto, rex será do tipo Cachorro(tipo de tempo de execução/tipo de objeto). Neste caso, podemos convencer o compilador de que o objeto rex será do tipo Cachorro em tempo de execução, realizando o casting, e com isso poderíamos utilizar os métodos específicos de cachorro. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Animal rex = new Cachorro();&lt;br&gt;
((Cachorro) rex).latir(); //casting para Cachorro&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Estado de um objeto&lt;br&gt;
O conjunto de todos os dados “armazenados” em um objeto é designado como seu “estado”. Na terminologia empregada em OO, os diversos dados de um objeto são atributos.&lt;br&gt;
Por exemplo, o objeto “cachorro” tem os atributos: nome, cor, raça, idade etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Os construtores devem definir o “estado inicial válido”&lt;br&gt;
Eventualmente, objetos precisam ser inicializados com um “estado mínimo” para serem considerados válidos. Exemplo:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Cachorro cachorro = new Cachorro(“Rex”, “marrom”, “Pitbull”,”médio”, “filhote”).&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso, sabemos que a classe Cachorro tem um construtor que define que ao criarmos um objeto do tipo Cachorro já devemos informar os atributos de nome, cor, raça e idade.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O conjunto de atributos e métodos públicos (visíveis) de um objeto constituem sua “interface” (Não confundir com a interface que podemos definir a um tipo de objeto).&lt;/li&gt;
&lt;li&gt;Classes menores são, pelo menos em teoria, modificadas com menor frequência, colaborando para a estabilidade do código e portanto tendem a ser mais coesas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Encapsulamento &lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
Consiste em esconder e proteger detalhes de uma classe, não permitindo que elementos de fora da classe tenham acesso às suas propriedades, evitando o acesso e a modificação direta dos objetos por "qualquer um".  Com isso, temos controle sobre como os dados são manipulados em uma classe, e portanto os detalhes de implementação dos métodos e atributos ficam restritos somente à quem interessa: a classe em si.&lt;/p&gt;

&lt;p&gt;Na POO, um atributo ou método que não é visível de fora do próprio objeto é chamado de "privado" e quando é visível, é chamado de "público".&lt;br&gt;
Por exemplo: Ao pisarmos no acelerador de um carro, não precisamos saber os detalhes de como o carro acelera, quais mecanismos são utilizados no processo. Nós só precisamos pisar no acelerador e o carro executa a ação, sem precisar nos expor como ele faz isso.&lt;/p&gt;

&lt;p&gt;A capacidade de um objeto “esconder” dados e comportamentos, é conhecido como hiding. Trata-se de um aspecto importante do encapsulamento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Herança&lt;u&gt;&lt;/u&gt;&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
Herança possibilita que um objeto receba comportamentos e estados de outro objeto.&lt;br&gt;
Ao utilizarmos herança em um objeto, herdamos características de todos os objetos acima dele, assim como nós herdamos características de nossos ancestrais. A herança a partir das características do objeto mais acima é considerada herança direta, enquanto as demais são consideradas heranças indiretas. Por exemplo, na família, a criança herda diretamente do pai e indiretamente do avô e do bisavô.&lt;/p&gt;

&lt;p&gt;Com isso, quando um objeto herda do outro dizemos que a classe que está sendo utilizado um relacionamento "É um". A classe que está herdando chamamos de subclasse, e a que está compartilhando as características chamamos de superclasse.&lt;/p&gt;

&lt;p&gt;Por exemplo: A classe “Cachorro” herda de “Animal”. Dizemos que um cachorro “é um” animal, e nesse caso o cachorro é a subclasse(ou classe filha) e animal é a superclasse, estabelecendo então uma relação de herança entre elas. &lt;/p&gt;

&lt;p&gt;Nesse relacionamento de herança podem ser herdados métodos públicos de instância e variáveis de instância privadas (que podem ser acessadas apenas por meio de métodos getters e setters públicos).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Em algumas linguagens existe a herança múltipla, onde um objeto pode herdar de diversos outros.&lt;/li&gt;
&lt;li&gt;Cuidado! Modelos com predominância de getters e setters podem estar disfarçando modelos anêmicos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Polimorfismo&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
A palavra"polimorfismo" vem do grego poli = muitas, morphos = forma. Na programação, consiste na capacidade de um mesmo método assumir diferentes formas.&lt;br&gt;
Ao herdarmos métodos de uma classe pai, por exemplo, é possível alterarmos o comportamento deles para se adequar ao objeto em questão, resultando em classes com métodos iguais mas com comportamentos diferentes. &lt;/p&gt;

&lt;p&gt;Por exemplo, “Carro” e “Moto” herdam de “Automóvel”. Todo “Automóvel” tem o método “acelerar” mas cada um acelera de um jeito, os mecanismos acionados para “Carro” e “Moto” são diferentes. Com isso, ambos irão herdar o método “acelerar” de “Automóvel”, mas irão modificar o seu comportamento e cada um irá acelerar de uma forma diferente.&lt;br&gt;
Ou seja, objetos diferentes que herdam de uma mesma classe e têm um mesmo método que é implementado de formas diferentes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Como todas as classes do java herdam de Object, todos os objetos do Java são considerados polimórficos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;u&gt;Sobrecarga de métodos&lt;/u&gt;&lt;/em&gt;&lt;br&gt;
A sobrecarga de métodos (method overload) possibilita que uma mesma classe possua métodos com o mesmo nome, mais de uma vez. Para isso acontecer, sua lista de parâmetros precisa ser diferente, para que o compilador possa diferenciá-los. Os tipos de retorno, modificadores de acesso e exceções lançadas também podem ser diferentes.&lt;/p&gt;

&lt;p&gt;Observação: métodos estáticos também podem sofrer sobrecarga.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;u&gt;Sobrescrita de métodos&lt;/u&gt;&lt;/em&gt;&lt;br&gt;
Se uma subclasse tem o mesmo método que foi declarado na superclasse, isso é conhecido como sobrescrita de métodos (method override). Para um método ser sobrescrito, deve manter a mesma assinatura.&lt;/p&gt;

&lt;p&gt;A assinatura de um método é composta por: modificador de visibilidade, tipo de retorno do método, parâmetros e exceções.&lt;/p&gt;

&lt;p&gt;Observações da sobrescrita de métodos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deve possuir o mesmo tipo de retorno: embora um retorno covariante nos permita alterar o tipo de retorno do método sobrescrito.&lt;/li&gt;
&lt;li&gt;Não pode possuir um modificador de acesso mais restritivo: deve possuir um modificador de acesso menos restritivo.&lt;/li&gt;
&lt;li&gt;Não deve lançar uma exceção verificada (checked exception) nova ou mais ampla: pode lançar exceções verificadas mais restritas e pode lançar qualquer exceção não verificada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Métodos estáticos e construtores  não podem ser sobrescritos, mas podem ser sobrecarregados. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;u&gt;Relacionamentos&lt;/u&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Relacionamento É UM: Um relacionamento É UM refere-se à herança ou implementação.&lt;/li&gt;
&lt;li&gt;Generalização: Generalização usa um relacionamento É UM de uma classe especializada para uma classe generalizada.&lt;/li&gt;
&lt;li&gt;Relacionamento TEM UM: Uma instância de uma classe TEM UMA referência para uma instância de outra classe.&lt;/li&gt;
&lt;li&gt;Agregação: Neste relacionamento, a existência de uma classe A e B não são dependentes umas das outras.
Para essa parte de agregação, vamos ver um exemplo da classe Student e da classe ContactInfo. Student (aluno) TEM UMA ContactInfo (informação de contato). ContactInfo pode ser usado em outros lugares – por exemplo, uma classe Employee (funcionário) de uma companhia também poderia utilizar a classe ContactInfo. Assim, Student pode existir sem ContactInfo e ContactInfo pode existir sem Student. Este tipo de relacionamento é conhecido como agregação.&lt;/li&gt;
&lt;li&gt;Composição: Neste relacionamento, a classe B não pode existir sem uma classe A – mas a classe A pode existir sem a classe B.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para dar uma ideia sobre composição, vamos ver esse exemplo da classe Student e a classe StudentId. Student TEM UM StudentId. Student pode existir sem StudentId, mas StudentId não pode existir sem Student. Esse tipo de relacionamento é conhecido como composição.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Abstração&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
Abstração é o processo de esconder os detalhes de implementação e exibir apenas as funcionalidades para o usuário.&lt;/p&gt;

&lt;p&gt;Um exemplo comum de abstração é o acelerador do carro: pisando mais forte, você aumenta a velocidade. Os motoristas, no entanto, não sabem como essa ação altera a velocidade – eles não precisam saber.&lt;/p&gt;

&lt;p&gt;Em Java, podemos obter abstração de duas maneiras: classes abstratas e interfaces.&lt;/p&gt;

&lt;p&gt;A palavra-chave abstract pode ser aplicada à classes e métodos. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;abstract e final ou static nunca podem estar juntas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se bem implementado, um código orientado a objetos terá, sempre menos dependência de implementações concretas e mais de abstrações.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Classes abstratas: Uma classe é abstrata quando ela contém a palavra reservada abstract.
Classes abstratas não podem ser instanciadas  (não é possível criar objetos de classes abstratas), portanto elas são projetadas para herança. Elas podem ter construtores, métodos estáticos, métodos concretos e métodos finais.&lt;/li&gt;
&lt;li&gt;Métodos abstratos: Um método é abstrato quando ele contém a palavra chave abstract.
Um método abstrato não possui implementação (não possui um corpo e termina com ponto e virgula). Métodos abstratos não devem ser marcados como private.&lt;/li&gt;
&lt;li&gt;Classes abstratas e métodos abstratos: 
Se pelo menos um método for abstrato dentro de uma classe, então toda a classe deve ser abstrata.
É possível ter uma classe abstrata sem nenhum método abstrato.
Podemos ter qualquer quantidade de métodos abstratos e não abstratos ao mesmo tempo na mesma classe.
A primeira classe concreta que herde de uma classe abstrata deve prover implementação para todos os métodos abstratos.
Caso a subclasse não implemente os métodos abstratos da superclasse, ela deve também ser marcada como abstrata.
Em um cenário real, a implementação vai ser feita por alguém desconhecido ao usuário final. Usuários não conhecem a classe de implementação nem os detalhes da implementação.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Quando vamos querer marcar uma classe como abstrata?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Para forçar subclasses a implementar métodos abstratos.&lt;/li&gt;
&lt;li&gt;Para impedir que existam objetos daquela classe.&lt;/li&gt;
&lt;li&gt;Para manter a referência à uma classe.
Para manter código comum.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Interface&lt;/em&gt;&lt;br&gt;
Uma interface é um template (ou uma "planta" de construção) de uma classe, projetada para ser implementada por outras classes. Ela possui apenas métodos abstratos (não possui métodos concretos) portanto seus métodos não tem “corpo”, apenas a assinatura.&lt;/p&gt;

&lt;p&gt;Quando uma classe implementa uma interface, ela é obrigada a implementar estes métodos abstratos da interface. Por isso, dizemos que uma interface é um "contrato", um conjunto de métodos que define que todas as classes que implementarem a interface devem possuir esses métodos. &lt;/p&gt;

&lt;p&gt;Por exemplo, uma interface “Funcionário” que possui os métodos “salario” e “comissao”. Esses métodos dentro da interface não possuem implementação, apenas a assinatura, o seu “nome”. As classes “Gerente”, “Diretor” e “Vendedor” implementam “Funcionário”. Nesse caso, todas elas serão obrigadas a implementar os métodos “salario” e “comissao”, definindo como eles devem funcionar em cada uma delas.&lt;/p&gt;

&lt;p&gt;Os métodos da interface são, por padrão, public e abstract. Então, dentro da interface, não precisamos especificar as palavras-chaves public e abstract.  Sendo assim, o modificador de acesso de um método implementado de uma interface deve ser public.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Um pequeno detalhe: uma interface não pode ser herdada por uma classe, mas sim implementada. No entanto, uma interface pode “herdar” de outra interface, criando uma hierarquia de interfaces. Usando um exemplo completo com carros, dizemos que a classe "Honda Fit Cross" herda da classe "Honda Fit", que por sua vez herda da classe "Carro". A classe "Carro" implementa a interface "Automóvel" que, por sua vez, pode herdar (por exemplo) uma interface chamada "MeioDeTransporte", uma vez que tanto um "automóvel" quanto uma "carroça" são meios de transporte, ainda que uma carroça não seja um automóvel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Métodos default e métodos estáticos nas Interfaces&lt;br&gt;
Normalmente, implementamos os métodos de uma interface em classes separadas. Digamos que seja necessário adicionar um novo método à interface. Então, deveremos implementar esse método em todas as outras classes que implementam essa interface também.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para evitar esse tipo de problema, a partir do Java, 8 foi introduzida a possibilidade de implementar métodos default e estáticos dentro de uma interface, além dos métodos abstratos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Interface de marcação&lt;br&gt;
São interfaces vazias. Por exemplo as interfaces Serializable, Cloneable e Remote. Servem apenas para oferecer algum tipo de “marcação” à uma classe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vantagens das interfaces&lt;br&gt;
Nos ajudam a utilizar a herança múltipla no Java.&lt;br&gt;
Elas fornecem abstração.&lt;br&gt;
Elas fornecem baixo acoplamento: os objetos são independentes uns dos outros.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quando vamos querer mudar de uma classe para uma interface?&lt;br&gt;
Para forçar subclasses a implementar métodos abstratos.&lt;br&gt;
Para evitar a criação de objetos dessa classe.&lt;br&gt;
Para manter a referência à uma classe.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Caso você queira definir métodos que podem ser necessários e código comum, use uma classe abstrata.&lt;br&gt;
Caso queira apenas definir métodos necessários, use uma interface. &lt;/p&gt;

&lt;p&gt;Fontes:&lt;br&gt;
&lt;a href="https://programacao-orientada-a-objetos.online/"&gt;https://programacao-orientada-a-objetos.online/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.freecodecamp.org/portuguese/news/principios-de-programacao-orientada-a-objetos-em-java-conceitos-de-poo-para-iniciantes/"&gt;https://www.freecodecamp.org/portuguese/news/principios-de-programacao-orientada-a-objetos-em-java-conceitos-de-poo-para-iniciantes/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oop</category>
      <category>java</category>
      <category>backend</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>Interfaces Funcionais no Java</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Mon, 07 Aug 2023 14:25:17 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/interfaces-funcionais-no-java-2lf8</link>
      <guid>https://forem.com/jeronimafloriano/interfaces-funcionais-no-java-2lf8</guid>
      <description>&lt;p&gt;Interfaces Funcionais são interfaces que contém apenas um método abstrato. Elas podem possuir qualquer quantidade de métodos padrão e estáticos, mas apenas um único método abstrato. São utilizadas em expressões lambda e referências a métodos, justamente pela característica de ter apenas um método abstrato, ou seja, quando implementamos um método de uma interface funcional o compilador consegue identificar que estamos nos referindo ao método abstrato da interface funcional em questão.&lt;/p&gt;

&lt;p&gt;Qualquer interface que se encaixe no critério mencionado é considerada uma interface funcional. Entretanto, podemos deixar isso mais explícito ao compilador com a anotação @FunctionalInterface em cima da interface. Essa anotação não é obrigatória, mas nos resguarda de erros: Se anotamos uma interface com @FunctionalInterface e por algum motivo acidental criarmos mais de um método abstrato na interface, o compilador já irá identificar um erro e nos avisará que a interface em questão só pode ter um método abstrato.&lt;/p&gt;

&lt;p&gt;O java nos oferece por padrão algumas interfaces funcionais que são bastante úteis com lambdas, mas também podemos criar nossas próprias interfaces funcionais, basta seguirmos o critério de ter apenas um método abstrato.&lt;br&gt;
Algumas interfaces funcionais bastante utilizadas são: Consumer, Predicate, Function e Supplier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumer: Aceita apenas um argumento (Generics) e não tem valor de retorno. &lt;/li&gt;
&lt;li&gt;Bi-Consumer: Recebe dois argumentos e não têm valor de retorno. &lt;/li&gt;
&lt;li&gt;Predicate : Aceita um único valor ou argumento e retorna uma resposta booleana (True/False). Pode ser implementada usando uma classe pelo implements.&lt;/li&gt;
&lt;li&gt;Bi-Predicate: Recebe dois argumentos e retorna um valor booleano.&lt;/li&gt;
&lt;li&gt;Function: Recebe um único argumento(Generics) e retorna um valor(Generics) após o processamento.&lt;/li&gt;
&lt;li&gt;Bi-Function: Recebe dois argumentos, enquanto Function aceita um argumento. &lt;/li&gt;
&lt;li&gt;Unary Operator and Binary Operator: Existem também duas outras interfaces funcionais que são nomeadas como Operador Unário e Operador Binário. Ambos estendem a Function e a Bi-Function, respectivamente. Em palavras simples, o operador unário estende a Function e o operador binário estende a Bi-Function. &lt;/li&gt;
&lt;li&gt;Supplier: Não recebe nenhuma entrada ou argumento e retorna uma única saída. Existem várias extensões da interface funcional Supplier, como BooleanSupplier, DoubleSupplier, LongSupplier e IntSupplier. O tipo de retorno de todas essas outras especializações são apenas suas primitivas correspondentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A interface funcional Predicate, por exemplo, é usada para testar uma condição em um objeto e retornar um valor booleano. No exemplo abaixo, vamos utilizar Predicate de duas formas: A primeira, para verificar se um número é maior que zero. Neste exemplo, definimos um Predicate chamado isGreaterThanZero que verifica se um número é maior que zero. Usamos o método test() do Predicate para testar a condição para diferentes números e imprimir o resultado booleano. &lt;br&gt;
Na segunda forma, temos uma lista de números contendo os números 1, 4 e 5 e utilizamos um predicate no método filter da classe Stream em uma função lambda, para filtrar os números pares (em que o resto da divisão por 2 é igual a 0).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QPGjUbJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ih6dpcc2hq6seg6xpzlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QPGjUbJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ih6dpcc2hq6seg6xpzlm.png" alt="interfaces funcionais java" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lembrando que podemos usar as interfaces funcionais em contextos mais complexos e principalmente no uso de expressões lambda.&lt;/p&gt;

</description>
      <category>java</category>
      <category>backend</category>
      <category>backenddevelopment</category>
      <category>poo</category>
    </item>
    <item>
      <title>Classe aninhadas no Java (Nested Classes)</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Wed, 02 Aug 2023 14:49:04 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/classe-aninhadas-no-java-nested-classes-545a</link>
      <guid>https://forem.com/jeronimafloriano/classe-aninhadas-no-java-nested-classes-545a</guid>
      <description>&lt;p&gt;Uma classe aninhada (Nested Classes) é definida dentro de outra. Seu objetivo é atender necessidades da sua classe envolvente. &lt;/p&gt;

&lt;p&gt;Há quatro tipos de classes aninhadas: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classes membro estáticas(static nested classes)&lt;/li&gt;
&lt;li&gt;Classes membro não estáticas(inner classes)&lt;/li&gt;
&lt;li&gt;Classes anônimas &lt;/li&gt;
&lt;li&gt;Classes locais&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Diferente das classes externas que só podem ter os modificadores de acesso  public or package private, essas classes podem ser private, public, protected or package private&lt;/p&gt;

&lt;p&gt;Outra diferença é que todas elas (exceto o primeiro tipo, por ser estática), são classificadas como classes internas. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nQxNqS5l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gj8hu1ra40l664rlat6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nQxNqS5l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gj8hu1ra40l664rlat6d.png" alt="Exemplos de Classes Aninhadas" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Classes membro estáticas: É como se fosse uma classe de nível superior estática comum, com a diferença de ter sido criada em outra classe de nível superior. Ela obedece as mesmas regras de acessibilidade que qualquer outro membro estático da classe em que está envolvida, e portanto NÃO possuem acesso e não podem se referir diretamente a variáveis ​​de instância ou métodos definidos em sua classe envolvente, podendo usá-los apenas por meio de uma referência de objeto. Ela também é instanciada da mesma forma que qualquer outra classe:&lt;br&gt;
ClasseAninhadaEstatica classeAninhadaEstatica = new ClasseAninhadaEstatica(); &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Classes membro não estáticas: Está sempre associada à classe em que está envolvida, por isso não pode ser acessada “de fora” e também não pode definir nenhum membro estático. Elas possuem acesso aos outros membros da classe envolvente, mesmo se eles forem private. Esse tipo de classe é comumente utilizada com o Padrão Adaptador. Ex: Interface Map, método keySet.&lt;br&gt;
Para instanciar uma classe interna, primeiro precisamos instanciar a classe externa.&lt;br&gt;
ClasseQualquer classeQualquer = new ClasseQualquer(); &lt;br&gt;
ClasseQualquer.ClasseMembro classeMembro = classeQualquer.new classeMembro();&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As classes locais e classes anônimas são tipos de classes internas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classes anônimas: Uma classe anônima é uma expressão. Elas permitem que você declare e instancie uma classe ao mesmo tempo. Existem apenas dentro do corpo de um método, SEM nomear a classe. É declarada e instanciada no momento da utilização, não têm nome e não são um membro de sua classe envolvente. Podem ser criadas em qualquer lugar do código em que uma expressão seja aceitável e por isso devem permanecer curtas(geralmente no máx. 10 linhas). Não permitem implementar muitas interfaces ou estender uma classe e implementar uma interface ao mesmo tempo. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As classes anônimas são ideais para implementar uma interface que contém dois ou mais métodos. Caso contenha um método só, podem ser declaradas como expressões lambdas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classes locais: Uma classe interna dentro do corpo de um método. Menos utilizadas, podem ser declaradas em qualquer lugar que uma variável local pode ser declarada e obedecem às mesmas regras de escopo. Também devem ser curtas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qual tipo de classe aninhada utilizar?&lt;br&gt;
Se uma classe aninhada precisa ser visível fora de um único método ou é muito longa, é recomendável utilizar uma classe membro. Se ela precisa de referência à sua classe envolvente, deve ser uma classe não-estática, mas caso contrário, deixe-a estática. &lt;/p&gt;

&lt;p&gt;Se a classe está dentro de um método, caso precise criar instâncias dela, utilize uma classe anônima. Se não, utilize uma classe local.&lt;/p&gt;

&lt;p&gt;*Baseado na documentação do Java e no livro "Java Efetivo".&lt;/p&gt;

</description>
      <category>java</category>
      <category>poo</category>
      <category>backend</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>A importância do Analista de Qualidade (QA) no time ágil</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Mon, 06 Mar 2023 16:32:03 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/a-importancia-do-analista-de-qualidade-qa-no-time-agil-1l77</link>
      <guid>https://forem.com/jeronimafloriano/a-importancia-do-analista-de-qualidade-qa-no-time-agil-1l77</guid>
      <description>&lt;p&gt;Quando o modelo cascata de desenvolvimento de software ainda era o mais utilizado nas empresas, hoje o papel que conhecemos de analista de qualidade geralmente era de uma pessoa responsável por realizar os testes manuais da aplicação, muitas vezes o próprio desenvolvedor ou analista de suporte que executava os testes ao final da etapa de codificação, após os requisitos do cliente serem desenvolvidos.&lt;/p&gt;

&lt;p&gt;Hoje no time ágil as entregas do produto são feitas de maneira constante e incremental onde as etapas são independentes e o software está em contanto evolução, e isso acarretou na necessidade de um foco ainda maior na qualidade do software, o que nos trouxe a figura do analista de qualidade que desempenha um papel de grande importância no time. Mais do que testes manuais, a qualidade é algo que deve estar presente muito antes da codificação, desde a análise dos requisitos do cliente até a integração e entrega contínua do software.&lt;/p&gt;

&lt;p&gt;Com isso, o QA participa de todo o ciclo de desenvolvimento desde o início do processo e precisa estar próximo do time atuando de maneira colaborativa com o PO, Scrum Master e os desenvolvedores, disseminando as boas práticas de qualidade para agregarmos valor na entrega ao cliente. &lt;/p&gt;

&lt;p&gt;Mais do que testes, esse profissional pode e deve auxiliar em etapas como a revisão e análise dos requisitos do projeto e o refinamento das demandas, utilizando seu conhecimento e olhar crítico para garantir que as informações estejam claras, objetivas e que as expectativas do cliente estejam sendo atendidas. Nessa etapa ele também já consegue ter as informações necessárias para iniciar o planejamento dos testes que serão executados, quais os recursos serão necessários e quais testes deverão ser automatizados, eliminando as repetições manuais de processos críticos e garantindo uma maior cobertura dos testes. Também é possível que o QA apoie no mapeamento dos processos do sistema, na análise de defeitos e identificação de causas raiz. &lt;/p&gt;

&lt;p&gt;São muitas as possibilidades e há vários outros pontos em que o QA pode auxiliar o time, tendo sendo como premissa ser um guardião e evangelizador de práticas de qualidade de forma que as entregas possam contribuir positivamente para os nossos clientes. Dessa forma conseguimos agregar ainda mais valor, otimizando o tempo, reduzindo os custos e aumentando a eficiência dos nossos processos.&lt;/p&gt;

</description>
      <category>qa</category>
      <category>qualityassurance</category>
      <category>agile</category>
      <category>testing</category>
    </item>
    <item>
      <title>Java Collections Framework</title>
      <dc:creator>Jeronima Floriano</dc:creator>
      <pubDate>Tue, 22 Nov 2022 17:34:51 +0000</pubDate>
      <link>https://forem.com/jeronimafloriano/java-collections-framework-1deb</link>
      <guid>https://forem.com/jeronimafloriano/java-collections-framework-1deb</guid>
      <description>&lt;p&gt;Uma coleção é um agrupamento de objetos, uma interação de vários objetos em um lugar só. Por exemplo, uma pasta com uma coleção de cartas, uma gaveta com várias chaves etc. Há vários tipos de coleções com diferentes particularidades.&lt;/p&gt;

&lt;p&gt;O Java possui uma arquitetura que representa várias coleções: o framework de coleções(Collections Framework). Esse framework nada mais é que a representação de todas as coleções existentes no java, um conjunto que engloba interfaces e classes que representam as estruturas de dados.&lt;/p&gt;

&lt;p&gt;Neste post iremos discorrer sobre o uso geral do Collections Framework, para que possamos ter o conhecimento necessário para escolhermos quando usar qual coleção.&lt;/p&gt;

&lt;p&gt;Toda coleção no java possui:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uma interface, que representa uma determinada coleção e nos permite manipulá-la independente de detalhes da implementação(Seguindo o padrão de programar voltado para a interface, não para a implementação).&lt;/li&gt;
&lt;li&gt;As implementações concretas das interfaces, para que possamos implementar de fato uma coleção.&lt;/li&gt;
&lt;li&gt;Métodos para manipularmos as coleções.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dentro do framework de collections, as interfaces encapsulam várias implementações de coleções, permitindo o acesso a uma coleção sem nos preocuparmos com os detalhes de implementação. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Yc_5qmvS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ll98me3xruqrp3hjte95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Yc_5qmvS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ll98me3xruqrp3hjte95.png" alt="Collections Framework" width="800" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A coleção principal no java é a interface Collection, e é dela que se originaram as demais interfaces. As principais interfaces do framework estendem diretamente de Collection, elas são o "core" do framework, o ponto principal das coleções.&lt;/p&gt;

&lt;p&gt;Cada coleção tem uma particularidade, por isso há várias coleções. Por exemplo, algumas permitem elementos duplicados e outros não, algumas são ordenadas e outras não são ordenadas (Veremos mais à frente quais são algumas dessas características).&lt;/p&gt;

&lt;p&gt;Todas as interfaces da coleção principal são genéricas. Por exemplo, esta é uma declaração da Collection:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;public interface Collection&amp;lt; E &amp;gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O uso de “&amp;lt; E &amp;gt;”  nos informa que a interface é genérica, ou seja, aceita qualquer tipo. Portanto, ao declarar uma instância de coleção devemos especificar o tipo de conteúdo do objeto na coleção, por exemplo:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collection&amp;lt; Strings &amp;gt; colecao;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lista a seguir descreve as principais interfaces e implementações do framework:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Collection&lt;/strong&gt;&lt;/u&gt; &lt;br&gt;
A raiz das coleções, todas as coleções implementam a Collection. Não há nenhuma implementação direta dessa interface, ela é a base de todas as coleções e possui os métodos básicos de toda coleção, como por exemplo: Métodos que informam quantos elementos há na coleção (size, isEmpty),  métodos que verificam se um determinado objeto está na coleção (contains),  métodos que adicionam e removem um elemento da coleção (add, remove) e métodos que fornecem um iterador sobre a coleção (iterador), dentre outros.&lt;/p&gt;

&lt;p&gt;Como a Collection é a raiz das coleções, podemos por exemplo “jogar” um Set dentro de um List e vice-versa, e assim usufruirmos dos métodos que precisarmos, pois ambas essas coleções implementam a interface Collection.  &lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;List&lt;/strong&gt;&lt;/u&gt;&lt;br&gt;
Uma coleção ordenada e sequencial, que pode conter elementos duplicados. Ela guarda a posição de seus elementos, nos permitindo buscar um elemento dentro de uma List pela sua posição.&lt;/p&gt;

&lt;p&gt;As principais implementações de List são: ArrayList, LinkedList e Vector.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ArrayList: Representa um array com redimensionamento dinâmico(o tamanho vai crescendo conforme são adicionados novos elementos). Possui acesso fácil e performático pelo índice. Os elementos precisam ser copiados para outro array quando não há mais capacidade e, quando uma posição é removida, ela precisa reposicionar as referências. Geralmente é a implementação de melhor desempenho&lt;/li&gt;
&lt;li&gt;LinkedList: Lista duplamente "linkada" (encadeada), que possui uma inserção e remoção performática em qualquer posição, pois nela o elemento B irá guardar qual é o elemento A(anterior a ele) e qual é o elemento C(posterior a ele). Ela também guarda o elemento inicial e o final da lista, e com isso ela não precisa reposicionar as referências quando uma posição é removida (como acontece no Arraylist). O acesso em uma LinkedList é mais demorado pelo índice, pois é preciso ficar pesquisando elemento por elemento (se tem um próximo, se tem um anterior...).&lt;/li&gt;
&lt;li&gt;Vector: Usa um array por baixo dos panos Serve para trabalhos com mais de uma trhead, pois é trhead-safe: enquanto uma pilha usa o recurso, a outra fica esperando para depois usá-lo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Set&lt;/strong&gt;&lt;/u&gt;&lt;br&gt;
É uma coleção usada para representar conjuntos. Um Set não pode conter elementos duplicados, e por isso é mais fácil adicionar e remover elementos, pois não é necessário percorrer todos os objetos ao adicionar/remover/procurar algum deles, como as Lists fazem.&lt;br&gt;
Também não segue uma ordem, é como uma "sacola" cheia de objetos dentro, onde eles estão todos misturados.&lt;/p&gt;

&lt;p&gt;A estrutura Set usa uma tabela de espalhamento para realizar mais rapidamente suas buscas. Com isso, ao buscar um objeto, em vez de comparar o objeto com todos os outros objetos contidos dentro do Set ela compara apenas os que possuem o mesmo hashcode. &lt;/p&gt;

&lt;p&gt;Suponha que temos uma Collection e desejamos criar outra Collection contendo os mesmos elementos mas com eliminando os elementos duplicados. Podemos fazer isso convertendo a Collection em alguma implementação de Set, copiando a implementação de Collection para um novo Set ou utilizando um Stream para converter em um Set.&lt;/p&gt;

&lt;p&gt;As implementações da interface Set mais utilizadas são: HashSet, LinkedHashSet e TreeSet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HashSet: Não guarda ordem, nem mesmo a ordem de inserção dos objetos. Um HashSet armazena seus elementos em uma tabela hash e é a implementação de melhor desempenho.&lt;/li&gt;
&lt;li&gt;LinkedHashSet:  É implementado como uma tabela de hash com uma lista vinculada passando por ela, guardando e ordenando com base na ordem de inserção dos objetos, ou seja, irá trazer os objetos de acordo com a ordem que eles foram inseridos. O LinkedHashSet poupa os usuários da ordem não especificada fornecida por HashSet, com uma leve perda de performance. &lt;/li&gt;
&lt;li&gt;TreeSet :Armazena os elementos em uma “árvore” os ordenando com base em seus valores, portanto só pode ser utilizado em classes que implementam o Comparable ou passando no construtor do TreeSet como parâmetro um objeto que implementa Comparator, para que assim ele possa fazer ordenações. Também é menos performático se comparado ao HashSet. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Queue&lt;/strong&gt;&lt;/u&gt;&lt;br&gt;
Uma fila usada para armazenar vários elementos antes do seu processamento. As filas normalmente ordenam os elementos de maneira FIFO (primeiro a entrar, primeiro a sair). As filas de prioridade (PriorityQueue) são uma exceção, pois ordenam os elementos de acordo com seus valores.&lt;/p&gt;

&lt;p&gt;Em uma fila FIFO, todos os novos elementos são inseridos no final da fila. Cada implementação de Queue deve especificar suas propriedades de ordenação. &lt;/p&gt;

&lt;p&gt;É possível que uma Queue implementação restrinja o número de elementos que contém; tais filas são conhecidas como limitadas.&lt;/p&gt;

&lt;p&gt;Algumas implementações de Queue são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AbstractQueue: A implementação de fila  mais simples possível  que o Java fornece.,  uma implementação básica da interface Queue.&lt;/li&gt;
&lt;li&gt;LinkedList&lt;/li&gt;
&lt;li&gt;PriorityQueu: Uma fila que ordena os elementos de acordo com seus valores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Deque&lt;/strong&gt;&lt;/u&gt;&lt;br&gt;
Uma coleção usada para armazenar vários elementos antes do processamento.  É uma fila de duas pontas, onde  todos os novos elementos podem ser inseridos, recuperados e removidos em ambos os extremos.&lt;br&gt;
Deques podem ser usados tanto como uma fila FIFO (primeiro a entrar, primeiro a sair) quanto uma pilha LIFO (último a entrar, primeiro a sair). Em um deque todos os novos elementos podem ser inseridos, recuperados e removidos em ambos os extremos.&lt;/p&gt;

&lt;p&gt;Algumas implementações de Deque:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ArrayDeque: Implementação de uma matriz redimensionável de uma Deque. Crescem conforme são adicionados novos elementos, não são thread-safe e não permitem elementos nulos.&lt;/li&gt;
&lt;li&gt;LinkedList&lt;/li&gt;
&lt;li&gt;ConcurrentLinkedDeque: Fornece suporte à operações simultâneas de inserção, remoção e acesso.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Map&lt;/strong&gt;&lt;/u&gt;&lt;br&gt;
Um objeto que mapeia chaves para valores e através da chave podemos acessar o valor correspondente. Map não pode conter chaves duplicadas,  cada chave pode mapear para no máximo um único valor. Se repetimos uma chave, a chave repetida é sobrescrita pela nova.&lt;/p&gt;

&lt;p&gt;A plataforma Java contém três Map implementações de uso geral: HashMap, TreeMap e LinkedHashMap. Seu comportamento e desempenho são precisamente análogos a HashSet, TreeSet, e LinkedHashSet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HashMap: Implementação baseada em tabela hash da interface Map. Não guarda ordem, nem mesmo a ordem de inserção dos objetos. Um HashMap armazena seus elementos em uma tabela hash e é a implementação de melhor desempenho.&lt;/li&gt;
&lt;li&gt;TreeMap: Uma implementação de Map que armazena os elementos em uma “árvore” os ordenando com base em seus valores, portanto só pode ser utilizado em classes que implementam o Comparable ou passando no construtor do TreeMap como parâmetro um objeto que implementa Comparator, para que assim ele possa fazer ordenações. &lt;/li&gt;
&lt;li&gt;LinkedHashMap: Tabela de hash e implementação de lista encadeada da interface Map que define a ordem de iteração, que normalmente é a ordem na qual as chaves foram inseridas no mapa(ordem de inserção).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As duas últimas interfaces de coleção principais são apenas versões classificadas de Set e Map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;SortedSet: Um Set que mantém seus elementos em ordem crescente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SortedMap: Um Map que mantém seus mapeamentos em ordem crescente de chaves. Este é o Map análogo de SortedSet.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;FONTE:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html"&gt;https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>backend</category>
      <category>ptbr</category>
    </item>
  </channel>
</rss>
