<?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>DEV Community: Ana Carolina Cortez</title>
    <description>The latest articles on DEV Community by Ana Carolina Cortez (@anaccortez).</description>
    <link>https://dev.to/anaccortez</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%2F2040052%2Fbb8ac7f5-5eab-4442-a9a2-55526f93d416.jpg</url>
      <title>DEV Community: Ana Carolina Cortez</title>
      <link>https://dev.to/anaccortez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anaccortez"/>
    <language>en</language>
    <item>
      <title>Python Básico para Jornalistas</title>
      <dc:creator>Ana Carolina Cortez</dc:creator>
      <pubDate>Sun, 22 Mar 2026 13:30:30 +0000</pubDate>
      <link>https://dev.to/anaccortez/python-basico-para-jornalistas-5aac</link>
      <guid>https://dev.to/anaccortez/python-basico-para-jornalistas-5aac</guid>
      <description>&lt;p&gt;Oi, pessoal, tudo bem?&lt;/p&gt;

&lt;p&gt;Andei sumida, mas quem é vivo sempre (re)aparece. Tenho focado meus estudos para além do backend e sigo buscando mais conhecimento em análise de dados, uma forma de trabalhar com a intersecção de dois mundos muito importantes para mim: programação e jornalismo, áreas nas quais tenho formação.&lt;/p&gt;

&lt;p&gt;Sou uma profissional multidisciplinar e adoro trajetórias de crescimento não lineares. Minha primeira formação é em jornalismo e trabalhei por dez anos na cobertura de economia em diversos veículos - foi isso, inclusive, o que me levou para a tecnologia. &lt;/p&gt;

&lt;p&gt;Ao buscar meios de coletar e analisar dados públicos para minhas pautas, cheguei à programação, automação e data science. E curti demais. &lt;/p&gt;

&lt;p&gt;Fiz transição para tecnologia em 2020 e, ao longo dos últimos anos, aprimorei habilidades de programação em Python, Java, SQL, Spring, FastAPI, mensageria, postgres, mongoDB, cloud (AWS), git, docker, serverless, APIs, testes... &lt;/p&gt;

&lt;p&gt;Nesse intervalo, trabalhei como desenvolvedora de automação por dois anos e de backend por mais três. Mais recentemente tenho me interessado também por IA e machine learning e quero seguir aprendendo.&lt;/p&gt;

&lt;p&gt;Como forma de compartilhar conhecimento de dados para além do mundo dev, criei um material de estudo e um canal no Youtube para meus colegas jornalistas. Afinal, programação não deve ser limitada ao mercado de tecnologia e precisa estar presente em todas as áreas do conhecimento, para automatizar tarefas rotineiras e facilitar o dia-a-dia de todo profissional.&lt;/p&gt;

&lt;p&gt;Aqui, deixo o link do repositório do github com o material do primeiro curso do canal, o Python Básico. O conteúdo contempla os fundamentos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;variáveis&lt;/li&gt;
&lt;li&gt;operadores&lt;/li&gt;
&lt;li&gt;manipulação de strings&lt;/li&gt;
&lt;li&gt;estruturas condicionais&lt;/li&gt;
&lt;li&gt;estruturas de repetição&lt;/li&gt;
&lt;li&gt;funções&lt;/li&gt;
&lt;li&gt;classes e métodos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LINK para o material didático, no google colab:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anacarolcortez" rel="noopener noreferrer"&gt;
        anacarolcortez
      &lt;/a&gt; / &lt;a href="https://github.com/anacarolcortez/material-didatico-python-para-jornalistas" rel="noopener noreferrer"&gt;
        material-didatico-python-para-jornalistas
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Notebook do meu curso gratuito e aberto sobre Python Básico para Jornalistas, com o objetivo de ensinar fundamentos para coleta, tratamento e análise de dados para enbasamento de pautas
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;🐍 Python Básico para Jornalistas&lt;/p&gt;
&lt;p&gt;Este repositório contém o material do curso Python Básico para Jornalistas, desenvolvido para introduzir profissionais de comunicação ao uso de Python aplicado à análise de dados.&lt;/p&gt;
&lt;p&gt;🎯 Objetivo&lt;/p&gt;
&lt;p&gt;O objetivo deste curso é ensinar os fundamentos da linguagem Python de forma prática e acessível, utilizando exemplos do dia a dia do jornalismo, como análise de acessos, manipulação de dados e automação de tarefas simples.&lt;/p&gt;
&lt;p&gt;Ao final do curso, você será capaz de:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Entender a lógica de programação&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trabalhar com estruturas básicas de dados&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Utilizar condicionais e loops&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Criar funções reutilizáveis&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🧠 Público-alvo&lt;/p&gt;
&lt;p&gt;Este material foi desenvolvido especialmente para:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Jornalistas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Estudantes de comunicação&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Profissionais interessados em jornalismo de dados&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Não é necessário conhecimento prévio em programação.&lt;/p&gt;
&lt;p&gt;📚 Conteúdo abordado&lt;/p&gt;
&lt;p&gt;O curso cobre os principais fundamentos de Python:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Variáveis e tipos de dados&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Operadores&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Strings&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Listas, dicionários, tuplas e conjuntos&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Estruturas condicionais&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Estruturas de repetição&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Funções&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tratamento…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/anacarolcortez/material-didatico-python-para-jornalistas" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Os próximos módulos incluirão:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;consulta de dados em APIs públicas com a biblioteca Requests&lt;/li&gt;
&lt;li&gt;análise de dados com Pandas&lt;/li&gt;
&lt;li&gt;webscraping (rapagem de dados) em sites dinâmicos com a biblioteca Selenium Webdriver&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Até mais =)&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>beginners</category>
      <category>automation</category>
    </item>
    <item>
      <title>Concorrência e paralelismo: o Golang performa melhor que o Java nesse quesito?</title>
      <dc:creator>Ana Carolina Cortez</dc:creator>
      <pubDate>Tue, 31 Dec 2024 20:17:50 +0000</pubDate>
      <link>https://dev.to/anaccortez/concorrencia-e-paralelismo-em-java-x-golang-3m93</link>
      <guid>https://dev.to/anaccortez/concorrencia-e-paralelismo-em-java-x-golang-3m93</guid>
      <description>&lt;p&gt;Uma das principais vantagens da Golang (ou Go), linguagem criada pela Google, é a gestão de concorrências, ou seja, a capacidade de rodar múltiplas tarefas ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;Toda linguagem moderna possui ferramentas para lidar com concorrência. O diferecial do Go está no fato de que o runtime abstrai a maioria dos detalhes sobre threads e paralelismo para nós, o que torna esse processamento muito mais simples. É o runtime, e não o kernel do sistema operacional, quem define como as goroutines são atribuídas às threads do sistema operacional e como as threads interagem com os núcleos da CPU disponíveis.&lt;/p&gt;

&lt;p&gt;O desenvolvedor pode utilizar concorrência (execução intercalada) e paralelismo (execução simultânea) ao mesmo tempo em Go. E pode fazer, inclusive, explicitamente, determinando a propriedade GOMAXPROCS qual o limite de threads simultâneas do programa. Assim o Go pode mapear goroutines em múltiplos núcleos para obter paralelismo real, e máquinas que possuam essa arquitetura no processamento. Por padrão, contudo, a runtime já faz essa abstração para nós.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import (
    "runtime"
)

func main() {
    runtime.GOMAXPROCS(4) // Permitir até 4 threads para paralelismo
}

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

&lt;/div&gt;



&lt;p&gt;Outras linguagens de programação também oferecem ferramentas para concorrência e paralelismo, mas o nível de abstração e simplicidade varia bastante. No Java, por exemplo, temos a API Concurrent (java.util.concurrent) e ferramentas como Thread, ExecutorService e ForkJoinPool para gerenciar concorrência e paralelismo.&lt;/p&gt;

&lt;p&gt;No entanto, o desenvolvedor precisa configurar manualmente o pool de threads ou usar ferramentas específicas como o CompletableFuture para simplificar operações assíncronas.&lt;/p&gt;

&lt;p&gt;Java também permite execução paralela em máquinas multicore usando pools de threads. Em contrapartida, porém, as threads em Java são mais pesadas porque são mapeadas diretamente para threads do sistema operacional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtime X Kernel
&lt;/h2&gt;

&lt;p&gt;As threads do sistema operacional são gerenciadas pelo kernel do sistema. Isso significa que a criação, destruição, troca de contexto e gerenciamento de threads são tarefas que o kernel executa, introduzindo overhead adicional. Cada thread do sistema operacional consome uma quantidade significativa de memória (normalmente em torno de 1 MB no Java). Quando o sistema alterna entre threads, ele precisa salvar e restaurar os estados do processador (registradores, pilha, etc.), o que é um processo caro.&lt;/p&gt;

&lt;p&gt;Já em Go, é o runtime da linguagem quem faz essa gestão. O Go não cria uma thread do sistema operacional para cada goroutine. Em vez disso, o runtime do Go gerencia múltiplas goroutines em um número muito menor de threads do sistema operacional - chamado tecnicamente de M:N scheduling (M goroutines em N threads). Isso permite &lt;br&gt;
milhares de goroutines com o mesmo número de threads sem sobrecarregar o sistema operacional .&lt;/p&gt;

&lt;p&gt;E é essa a "graça" da linguagem, fazendo dela a queridinha para gerenciar sistemas distribuídos de alta performance e aplicações de processamento de dados em tempo real.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Porém, entretanto, todavia, é importante ressaltar que qualquer linguagem moderna é capaz de trabalhar com concorrência e paralelismo. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A diferença está na leveza e no custo de processamento. &lt;/p&gt;

&lt;p&gt;Desta forma, não precisamos ficar num FlaxFlu de linguagens. Cada linguagem tem sua magia, seus pontos fortes e pontos fracos.&lt;/p&gt;

&lt;p&gt;Apenas para mostrar como qualquer linguagem pode se incumbir dessas tarefas, vou exemplificar em Go e em Java como um mesmo programa é codificado, cada um com suas particularidades. A ideia é simples: simular uma tarefa realizada com concorrência e paralelismo e imprimir o tempo de execução e o uso de memória em ambos os casos (os números variam para cada máquina). &lt;/p&gt;

&lt;p&gt;Para tornar a comparação mais "isenta", pedi para o &lt;strong&gt;chatgpt&lt;/strong&gt; gerar os códigos, que estão abaixo:&lt;/p&gt;
&lt;h3&gt;
  
  
  Golang
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

func tarefa(id int) {
    // Simula algum processamento leve
    time.Sleep(10 * time.Millisecond)
}

func main() {
    // Configura a quantidade de tarefas
    numTarefas := 100000

    // Medindo o tempo de execução
    start := time.Now()

    var wg sync.WaitGroup
    wg.Add(numTarefas)

    // Calculando a quantidade de memória usada
    var m runtime.MemStats
    runtime.ReadMemStats(&amp;amp;m)
    initialMemory := m.Sys

    // Criando as goroutines para simular o trabalho
    for i := 0; i &amp;lt; numTarefas; i++ {
        go func(id int) {
            defer wg.Done()
            tarefa(id)
        }(i)
    }

    wg.Wait() // Espera todas as goroutines terminarem

    // Calculando o tempo total de execução e a memória usada
    elapsed := time.Since(start)
    runtime.ReadMemStats(&amp;amp;m)
    finalMemory := m.Sys

    // Printando os resultados
    fmt.Printf("Tempo de execução: %s\n", elapsed)
    fmt.Printf("Memória utilizada: %d bytes\n", finalMemory-initialMemory)
}

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

&lt;/div&gt;


&lt;p&gt;Tempo de execução: 141.886206ms&lt;br&gt;
Memória utilizada: 43909120 bytes&lt;/p&gt;
&lt;h3&gt;
  
  
  Java
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.concurrent.*;
import java.util.*;

public class ConcorrenciaParalelismoJava {

    // Função que simula uma tarefa e faz um pequeno processamento
    public static void tarefa(int id) throws InterruptedException {
        Thread.sleep(10); // Simula um pequeno tempo de processamento
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // Configura a quantidade de tarefas
        int numTarefas = 100000;

        // Medindo o tempo de execução
        long start = System.nanoTime();

        // ExecutorService para gerenciar o pool de threads
        ExecutorService executor = Executors.newFixedThreadPool(100);

        List&amp;lt;Future&amp;lt;Void&amp;gt;&amp;gt; futures = new ArrayList&amp;lt;&amp;gt;();

        // Criando as threads para simular o trabalho
        for (int i = 0; i &amp;lt; numTarefas; i++) {
            final int tarefaId = i;
            futures.add(executor.submit(() -&amp;gt; {
                tarefa(tarefaId);
                return null;
            }));
        }

        // Espera todas as tarefas terminarem
        for (Future&amp;lt;Void&amp;gt; future : futures) {
            future.get();
        }

        executor.shutdown();

        // Calculando o tempo total de execução
        long elapsed = System.nanoTime() - start;
        System.out.println("Tempo de execução: " + (elapsed / 1_000_000) + " ms");

        // Medindo o uso de memória (em bytes)
        Runtime runtime = Runtime.getRuntime();
        long memoryUsed = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("Memória utilizada: " + memoryUsed + " bytes");
    }
}

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

&lt;/div&gt;


&lt;p&gt;Tempo de execução: 10238 ms&lt;br&gt;
Memória utilizada: 106732888 bytes&lt;/p&gt;

&lt;p&gt;Enfim, claramente podemos executar exatamente a mesma tarefa nas duas linguagens. Cada uma utilizando suas bibliotecas para os devidos fins. Nota-se que em Go a execução foi mais 98,61% mais rápida e gastou-se 58,86% menos memória. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mas não existe linguagem melhor que outra. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O que precisamos apenas é entender dos prós e contras de cada uma na hora de escolher qual linguagem pode nos ajudar a resolver os problemas que temos nos nossos projetos. E cada projeto vai ter seu pool de problemas particulares e singulares que precisam ser resolvidos.&lt;/p&gt;
&lt;h3&gt;
  
  
  Otimização em Java
&lt;/h3&gt;

&lt;p&gt;É possível, claro, usar de estratégias para tentar melhorar o desempenho do código fornecido acima em Java.&lt;/p&gt;

&lt;p&gt;Pedi novamente para o chatgpt incorporar algumas cartas na manga no código inicial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

public class ForkJoinPoolOtimizacao {

    public static void tarefa(int id) throws InterruptedException {
        Thread.sleep(10); // Simula algum processamento leve
    }

    public static void main(String[] args) throws InterruptedException {
        int numTarefas = 100000;

        // Criando um ForkJoinPool personalizado com mais threads
        ForkJoinPool pool = new ForkJoinPool(100); // Ajuste o número de threads conforme necessário

        // Medindo o tempo de execução
        long start = System.nanoTime();

        // Submetendo tarefas ao ForkJoinPool
        pool.submit(() -&amp;gt; {
            IntStream.range(0, numTarefas).parallel().forEach(id -&amp;gt; {
                try {
                    tarefa(id);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }).join();

        long elapsed = System.nanoTime() - start;

        pool.shutdown();

        System.out.println("Tempo de execução: " + (elapsed / 1_000_000) + " ms");

        // Medindo o uso de memória
        Runtime runtime = Runtime.getRuntime();
        long memoryUsed = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("Memória utilizada: " + memoryUsed + " bytes");
    }
}

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

&lt;/div&gt;



&lt;p&gt;Para reduzir o consumo de memória, utilizamos um ForkJoinPool, com um número maior de threads (100) para lidar melhor com a alta simultaneidade. Isso substitui o pool de threads padrão, garantindo que mais tarefas possam ser executadas simultaneamente. Também chamamos submit e join para garantir que todas as tarefas sejam concluídas antes de finalizar o programa.&lt;/p&gt;

&lt;p&gt;Com essas mudanças, reduziu-se a alocação de memória em 56,21%:&lt;/p&gt;

&lt;p&gt;Tempo de execução: 11877 ms&lt;br&gt;
Memória utilizada: 46733064 bytes&lt;/p&gt;

&lt;p&gt;Otimizar esse código é um desafio interessante. Fica o convite para você fazer melhor usando Java, o que é sempre muito possível, já que essa linguagem, sabemos, é maravilhosa independentemente de qualquer detalhe.&lt;/p&gt;

</description>
      <category>go</category>
      <category>java</category>
      <category>concorrencia</category>
      <category>paralelismo</category>
    </item>
    <item>
      <title>array[]: uma classe especial gerenciada internamente pela própria JVM</title>
      <dc:creator>Ana Carolina Cortez</dc:creator>
      <pubDate>Thu, 12 Sep 2024 11:47:46 +0000</pubDate>
      <link>https://dev.to/anaccortez/array-uma-classe-especial-gerenciada-internamente-pela-propria-jvm-o3c</link>
      <guid>https://dev.to/anaccortez/array-uma-classe-especial-gerenciada-internamente-pela-propria-jvm-o3c</guid>
      <description>&lt;p&gt;A primeira forma como todos nós somos introduzidos ao estudo de estruturas de dados em Java (e em outras linguagens) é por meio de arrays. Em Java, array é uma classe, um objeto, filha de Object (como todas as classes são). Porém, ela é uma classe com tratamento especial na linguagem.&lt;/p&gt;

&lt;p&gt;Ao contrário de classes e objetos comuns, a sintaxe de arrays e seu tratamento é gerenciado diretamente pelo compilador e pela JVM (Java Virtual Machine). Isso inclui a forma como os arrays são alocados, manipulados e acessados. Essa classe, inclusive, não é encontrada diretamente no código-fonte.&lt;/p&gt;

&lt;p&gt;O Java trata automaticamente os arrays como instâncias dessa classe especial.&lt;/p&gt;

&lt;p&gt;Se você rodar o código abaixo vai perceber os seguintes outputs:&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 Main
{
    public static void main(String[] args) {
        int[] intArray = new int[5];
        System.out.println(intArray.getClass().getName());
        System.out.println(intArray.getClass().getSuperclass());
    }
}

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

&lt;/div&gt;



&lt;p&gt;[I&lt;br&gt;
class java.lang.Object&lt;/p&gt;

&lt;p&gt;Esse nome de classe "[I" é apenas um nome simbólico gerado automaticamente, que a JVM usa para representar um array de inteiros (int[]). Cada tipo tem seu próprio nome simbólico:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl48oykrfwta2r4nybdj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl48oykrfwta2r4nybdj6.png" alt=" " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Os colchetes "[" indicam as dimensões. Um array unidimensional é repreentado por [, enquanto o bidimensional por [[, o tridimensional por [[[... e assim por diante.&lt;/p&gt;
&lt;h2&gt;
  
  
  Declaração
&lt;/h2&gt;

&lt;p&gt;Para declarar e inicializar um array, é importante explicitar o tipo de dado e o tamanho do objeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int[] intArray = new int[5]; //array de tamanho 5
char[] charArray = new char[]{'a', 'b', 'c'}; //o compilador entende que é um array de tamanho 3
double[] doubleArray = {1.2, 1.3, 1.4, 1.5}; //o compilador entende que é um array de tamanho 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Java permite colocar os colchetes no nome da variável, em vez do tipo, por exemplo: int intArray[] = new int[5]. Porém, isso não é recomendado, pois foge da convenção.&lt;/p&gt;

&lt;p&gt;Os dados armazenados dentro de arrays podem ser alocados na memória de forma "contígua", ou seja, sequencialmente, pela JVM. Para acessar os dados, utilizam-se índices e o primeiro índice de um array é sempre 0 em Java.&lt;/p&gt;

&lt;p&gt;Por exemplo, para acessar a letra 'a' do charArray acima, é preciso buscá-lo por charArray[0]. A letra 'b', por sua vez, está em charArray[1] e, a letra 'c', em charArray[2]. Se você tentar acessar um índice que não existe no array, você receberá um erro de "IndexOutOfBounce". Por exemplo, no caso de eu tentar acessar o valor em charArray[3]. &lt;/p&gt;

&lt;p&gt;O tamanho de um array, uma vez definido na declaração, não poderá jamais ser alterado. Se eu declarei que charArray teria 3 elementos, ele não vai comportar mais que isso. Menos sim... mais, não.&lt;/p&gt;

&lt;p&gt;E aqui, um adendo. Os valores não preenchidos de um array assumirão o mesmo valor padrão do tipo do array. Por exemplo, em um array de inteiros, os valores vazios serão preenchidos com 0. Em um array de boolean, com false. Em um array de string, com null.&lt;/p&gt;

&lt;p&gt;Assim como o tamanho, o tipo de um array não pode ser alterado. Mas é possível copiar arrays com tipos diferentes, se estes forem subtipos de um mesmo tipo. Confuso, né? Um exemplo ajuda: Integer e Double são subtipos de Number. Então...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Integer[] integerArray = {1, 2, 3};
Number[] numberArray = intgerArray;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse código é aceito pelo compilador. Porém, é preciso cautela. Se fizermos isso aqui, geraremos um erro de compilação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;numberArray[0] = 1.2;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso porque integerArray e numberArray apontam para o mesmo espaço de memória. Ainda que numberArray comporte um double como primeiro elemento, o integerArray não comporta e, portanto, o numberArray não tem "permissão" de alterar o valor de índice 0 por um tipo double.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memória
&lt;/h2&gt;

&lt;p&gt;Um array pode armazenar sempre dados de um mesmo tipo, aceitando primitivos e objetos. Se o array é de inteiros, ele não vai aceitar char, double, float, String... somente valores inteiros.&lt;/p&gt;

&lt;p&gt;O array em si, é uma classe (ainda que especial) e, portanto, é guardado na Heap. Desta forma, o array armazena um endereço de memória que, por sua vez, contém os valores inputados no array.&lt;/p&gt;

&lt;p&gt;Um array de primitivos aloca blocos de memória contíguos para armazenar os valores diretamente, enquanto o array de objetos armazena referências (ponteiros) para objetos, localizados em outros lugares da memória.&lt;/p&gt;

&lt;p&gt;Isso significa que tanto os arrays de tipos primitivos (como int[]) quanto os arrays de objetos (como String[]) são armazenados na heap. No caso de arrays de tipos primitivos, os valores dos elementos do array também são armazenados diretamente na heap, contiguamente ao próprio array. Já no caso do array de objetos, os objetos apontados por essas referências podem estar alocados em diferentes locais da heap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Métodos
&lt;/h2&gt;

&lt;p&gt;Todas as classes de array tem os métodos length e cloning. O primeiro retorna o tamanho do array e, o segundo, faz uma cópia do array para um outro array (no caso, do ponteiro para o mesmo endereço de memória).&lt;/p&gt;

&lt;p&gt;Porém, como filho da classe Object (assim como todas as classes em Java), o array possui também os métodos da superclasse: toString, equals e hashCode.&lt;/p&gt;

&lt;p&gt;Utilizar arrays por baixo dos panos, contudo, é o que mais acontece na vida real. Ainda que os arrays sejam performáticos, é bem mais complicado iterar os seus elementos e há classes que fazem abstrações em cima de arrays que tornam a vida do programador muito mais simples.&lt;/p&gt;

&lt;p&gt;Esse é o caso da classe Arrays (com letra maiúscula). Ela basicamente empacota arrays em uma classe padrão do Java e apresenta uma série de métodos bem simples de implementar para trabalhar com os dados. A classe Arrays tem mais uma vantagem poderosa: ela trabalha com alocação dinâmica, então é mais fácil de lidar com coleções - afinal, raramente a gente sabe o tamanho exato do array que podemos precisar. A classe Arrays consegue expandir o tamanho da coleção sob demanda, sem que o programador tenha que ficar criando novos arrays (com letra minúscula) de tamanhos maiores  e copiando os dados do array anterior, que ficou pequeno demais de repente.&lt;/p&gt;

&lt;p&gt;Os arrays também são a base de classes como List, Stack e Queue (que fazem basicamente um wrap e incluem métodos muito bons para lidar com os dados).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Já parou para pensar que String é uma classe que abstrai um array de char?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffru0e3erqzcixvk9kdtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffru0e3erqzcixvk9kdtm.png" alt=" " width="429" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dimensões
&lt;/h2&gt;

&lt;p&gt;Um array multidimensional é um array de objetos, já que um array é um objeto em si. Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int[][] arrayInt = new int[5][2];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste caso, é correto dizer que o array de int recebe 5 objetos de tamanho 2. Em Java, um array bidimensional é na verdade um array de arrays unidimensionais. Ou seja, no exemplo, temos um array contendo 5 elementos, onde cada elemento é um array de 2 inteiros (int[]).&lt;/p&gt;

&lt;p&gt;O arrayInt é um array de 5 referências (objetos). Cada uma dessas referências aponta para um array unidimensional de 2 inteiros (int[]).&lt;br&gt;
Em termos mais simples, você tem 5 objetos (arrays unidimensionais) de 2 inteiros cada um.&lt;/p&gt;

&lt;p&gt;Para iterar sobre arrays multidimensionais geralmente utiliza-se uma cadeia de loops.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int[][] arrayInt = new int[5][2]; // Array 5x2

int value = 1; // Valor inicial para preencher o array

for (int i = 0; i &amp;lt; arrayInt.length; i++) {           // Itera sobre as linhas (5 linhas)
    for (int j = 0; j &amp;lt; arrayInt[i].length; j++) {     // Itera sobre as colunas (2 colunas)
        arrayInt[i][j] = value++;                      // Atribui o valor e incrementa
    }
}

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

&lt;/div&gt;



&lt;p&gt;Resultado:&lt;br&gt;
[&lt;br&gt;
 [1, 2],&lt;br&gt;
 [3, 4],&lt;br&gt;
 [5, 6],&lt;br&gt;
 [7, 8],&lt;br&gt;
 [9, 10]&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Arrays são objetos e eles pondem apontar para outros objetos. Mas, é preciso cautela nesse entendimento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Object[] oa = new int[2][3];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso compila porque o tipo int[2][3] é um array bidimensional de inteiros, ou seja, é um array de arrays de inteiros. Um array de qualquer tipo é um objeto em Java, e arrays multidimensionais são arrays de arrays. Portanto, int[2][3] é na verdade um array de int[], e você está atribuindo este array de int[] a uma variável do tipo Object[]. Isso é permitido, pois um array de qualquer tipo pode ser armazenado como Object[].&lt;/p&gt;

&lt;p&gt;Mas...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Object[][] oaa = new int[2][3];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não compila. Em Java, arrays têm tipos fortes e a relação entre int[] e Object[] não se aplica aqui. Um array de int&lt;a href="https://dev.toque%20%C3%A9%20o%20que%20int[2][3]%20representa"&gt;&lt;/a&gt; não é considerado um array de Object[], porque tipos primitivos (int, char, etc.) não podem ser diretamente atribuídos a variáveis do tipo Object.&lt;/p&gt;

&lt;p&gt;O compilador espera que cada elemento de Object[][] seja do tipo Object[], mas int[] não pode ser convertido implicitamente para Object[], pois int é um tipo primitivo.&lt;/p&gt;

&lt;p&gt;Em suma, o primeiro compila porque um array bidimensional de inteiros é tratado como um array de arrays (int[][]), que pode ser armazenado como Object[]. O segundo não compila porque um array de int&lt;a href="https://dev.toque%20%C3%A9%20um%20array%20de%20tipos%20primitivos"&gt;&lt;/a&gt; não pode ser atribuído a um array de Object[].&lt;/p&gt;

</description>
      <category>java</category>
      <category>array</category>
      <category>jvm</category>
      <category>object</category>
    </item>
    <item>
      <title>Cuidados com transferência de tipos em Java</title>
      <dc:creator>Ana Carolina Cortez</dc:creator>
      <pubDate>Wed, 11 Sep 2024 23:28:58 +0000</pubDate>
      <link>https://dev.to/anaccortez/cuidados-com-transferencia-de-tipos-em-java-10he</link>
      <guid>https://dev.to/anaccortez/cuidados-com-transferencia-de-tipos-em-java-10he</guid>
      <description>&lt;p&gt;Java é ua linguagem fortemente tipada, mas ainda assim é possível transferir valores entre variáveis primitivas de tipos diferentes. Por exemplo, eu posso atribuir o valor de um int para um double sem problemas, contanto que a capacidade de armazenamento do tipo que recebe o valor aguente. &lt;/p&gt;

&lt;p&gt;Veja abaixo qual o tamanho que cada tipo primitivo comporta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvh45nnim612uv99drzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzvh45nnim612uv99drzo.png" alt=" " width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Transferir valor para um tipo com maior capacidade de armazenamento tem um nome técnico: "widening conversion". O termo em português é geralmente traduzido como "conversão de ampliação" ou "conversão de alargamento". Ele se refere ao processo em que um valor de um tipo de dado menor ou mais restrito é convertido para um tipo maior ou mais abrangente, sem perda de informação. &lt;/p&gt;

&lt;p&gt;Mas, e se eu quiser transferir o valor para um tipo com menor capacidade de armazenamento? O compilador do Java não gosta disso, mas ele permitirá se você fizer um "cast", como no exemplo abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double decimal = 65.9;
int i = (int) decimal; //aqui ele perde a casa decimal e vira 65
char c = (char) i; //aqui ele vira a letra A (que corresponde a 65)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o tamanho do valor que irá para o novo tipo exceder os limites desse tipo, algo mais dramático pode acontecer. Um int i = 10 cabe em uma variável byte, pois ela comporta 8 bits em um intervalo de -128 a +127. Porém, e se eu quiser colocar um int i = 128 em uma variável do tipo byte... haverá perda de informação.&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 Main
{
    public static void main(String[] args) {
        int i = 128;
        byte b = (byte) i;

        System.out.println(b); // o valor de b agora é -128 :S
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Autoboxing
&lt;/h2&gt;

&lt;p&gt;No post passado [&lt;a href="https://dev.to/anaccortez/tipos-primitivos-vs-referencias-em-java-e-a-imutabilidade-das-strings-2n0j"&gt;leia ele aqui&lt;/a&gt;], eu falei um pouco das classes Wrapper. Como exemplo, eu tinha escrito Integer.parse(i) = imagine que i é um tipo &lt;br&gt;
primitivo int. &lt;/p&gt;

&lt;p&gt;Atualmente, utilizar o método parse do Wrapper não é mais encorajado, pois está depreciado. Para transformar um primitivo em uma classe Wrapper e, desta forma, utilizar métodos built-in, é recomendado fazer um "autoboxing", como no exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Character ch = 'a';
Integer i = 10;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note que é uma abordagem mais direta. Simplesmente atribui-se o valor logo de uma vez.&lt;/p&gt;

&lt;p&gt;Para fazer o caminho inverso e retomar o dado como tipo primitivo, você pode fazer o "unboxing", utilizando o método valueOf:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Integer i = 10;
int j = Integer.valueOf(i);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fazer o Wrapper de um primitivo, como eu já disse no post anterior, tem a vantagem de permitir utilizar os métodos da classe e facilitar a vida na hora de trabalhar com os dados.&lt;/p&gt;

&lt;p&gt;A versão wrapper de um primitivo pode se parecer muito com ele à primeira-vista, mas a JVM não trata um objeto e um primitivo da mesma forma, não se esqueça. Lembre-se que os primitivos vão para a Stack e os objetos para a Heap [&lt;a href="https://dev.to/anaccortez/heap-vs-stack-como-o-java-gerencia-o-que-deve-ser-lembrado-ou-esquecido-3ndm"&gt;relembre aqui&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;Em termos de performance, claro que recuperar dados de um primitivo é menos custoso para o computador, visto que o valor é armazenado diretamente, e não por referência. É muito mais rápido pegar um dado pronto do que ficar juntando os pedacinhos dele na memória.&lt;/p&gt;

&lt;p&gt;Mas há casos que utilizar um Wrapper será indispensável. Por exemplo, quando você quiser trabalhar com a classe ArrayList. Ela só aceita objetos como parâmetros, e não valores primitivos.&lt;/p&gt;

&lt;p&gt;A flexibilidade que essa transformação de primitivo para objeto e vice-versa traz é muito bacana da linguagem. Mas precisamos ficar atentos a essas armailhas discutidas aqui e muitas outras. &lt;/p&gt;

&lt;p&gt;Apenas para chocar a sociedade (rs) vou dar o exemplo de um caso problemático envolvendo o comportamento inesperado de um código ao trabalhar com overloading (ainda não fiz post de overloading, mas vou fazer. Basicamente, overloading ocorre quando um método possui diferentes assinaturas).&lt;/p&gt;

&lt;p&gt;Esse caso foi citado no livro "Java Efetivo", do Joshua Bloch.&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 SetListTest {
    public static void main(String[] args) {
        Set&amp;lt;Integer&amp;gt; set = new TreeSet&amp;lt;&amp;gt;();
        List&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

        for (int i = -3; i &amp;lt; 3; i++) {
            set.add(i);
            list.add(i);
        }

        for (int i = 0; i &amp;lt; 3; i++) {
            set.remove(i);
            list.remove(i); // como corrigir: list.remove((Integer) i);
        }

        System.out.println(set + " " + list);

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

&lt;/div&gt;



&lt;p&gt;Neste programa, o objetivo era adicionar a um set e a uma lista valores inteiros de -3 a 2 [-3, -2, -1, 0, 1, 2]. Em seguida, excluir os valores positivos [0, 1 e 2]. Mas, se você rodar esse código, você vai perceber que o set e o list não apresentaram o mesmo resultado. O set retorna [-3, -2, -1], como esperado. Já o list retorna [-2, 0, 2].&lt;/p&gt;

&lt;p&gt;Isso acontece porque a chamada para o método built-in remove(i) da classe List trata o i como um tipo primitivo int, e nada mais. O método, por sua vez, remove os elementos na posição i.&lt;/p&gt;

&lt;p&gt;Já a chamada para o método remove(i) da classe Set chama um overload que recebe como parâmetro um objeto Integer, convertendo automaticamente i, que era originalmente um int, para Integer. O comportamento desse método, por sua vez, exclui do conjunto os elementos que tiverem valor igual a i (e não o índice igual a i) - note que o tipo esperado tanto para o set quanto para o list era Integer. (Set set / List list). Por isso que o overloading escolhido para o método remove, da classe Set, fez a conversão para Integer.&lt;/p&gt;

&lt;p&gt;Enquanto o comportamento de remove em List é excluir pelo índice, o do remove em Set é excluir pelo valor. Tudo por conta de um overloading de remove que recebe Integer.&lt;/p&gt;

</description>
      <category>java</category>
      <category>autoboxing</category>
      <category>wrapper</category>
      <category>tiposprimitivos</category>
    </item>
    <item>
      <title>Tipos primitivos vs referências em Java e a imutabilidade das Strings</title>
      <dc:creator>Ana Carolina Cortez</dc:creator>
      <pubDate>Tue, 10 Sep 2024 15:27:38 +0000</pubDate>
      <link>https://dev.to/anaccortez/tipos-primitivos-vs-referencias-em-java-e-a-imutabilidade-das-strings-2n0j</link>
      <guid>https://dev.to/anaccortez/tipos-primitivos-vs-referencias-em-java-e-a-imutabilidade-das-strings-2n0j</guid>
      <description>&lt;p&gt;Em Java temos dois tipos de dados (ou variáveis): os primitivos e os não-primitivos (também chamados de referências).&lt;/p&gt;

&lt;p&gt;Os &lt;strong&gt;tipos primitivos&lt;/strong&gt; têm os seus valores literais guardados na Stack, memória de armazenamento temporário e de curta duração, gerenciada pela Java Virtual Machine (JVM). [&lt;a href="https://dev.to/anaccortez/heap-vs-stack-como-o-java-gerencia-o-que-deve-ser-lembrado-ou-esquecido-3ndm"&gt;leia mais sobre os tipos de memória aqui&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;As variáveis primitivas são divididas em quatro grupos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Tipos inteiros:&lt;/strong&gt; utilizados para armazenar números inteiros (sem parte decimal). São eles: byte, short, int, long. O long possui a letra "L" ou "l" ao final do número, para diferenciação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Tipos de ponto flutuante:&lt;/strong&gt;: Usados para armazenar números com parte decimal (números reais). São eles: float, double. O float possui a letra "F" ou "f" ao final do número, para diferenciação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Tipo caractere:&lt;/strong&gt; Utilizado para armazenar caracteres únicos (como letras, dígitos ou símbolos): char. São inicializados com aspas simples '', em vez de duplas "".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Tipo boleano:&lt;/strong&gt; Utilizado para armazenar valores lógicos (true ou false): bool&lt;/p&gt;

&lt;p&gt;Veja na tabela abaixo qual o intervalo de valores que cada tipo comporta, além de seus valores "default" (padrão):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g7psqt62gz8hbhfczoc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g7psqt62gz8hbhfczoc.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Em formato científico, o E representa um expoente. Por exemplo, 1.23E+10, é igual a 1,23 x 10^10&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;O que é um valor padrão? É o valor que a variável vai assumir caso ela não tenha sido inicializada. Para assumir esse valor, contudo, ela precisa ser global ou constantes (final).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public final boolean isTrue;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nessa linha de código, a variável "isTrue" não foi inicializada, mas o compilador não apresentará erro, pois ele mesmo vai considerar o valor padrão "false" para a variável boleana.&lt;/p&gt;

&lt;p&gt;Aqui, um alerta importante: se o escopo da variável for local, ou seja, se ela tiver sido declarada dentro de uma função, nós, programadores, seremos obrigados a atribuir um valor para ela. Caso contrário, haverá um erro de compilação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void teste(){
        int i = 2;
        int j;

        if (i &amp;lt; 10){
            j = 5;
        }

        System.out.println(j);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, ainda que saibamos que "2 &amp;lt; 10" retorna "true", o compilador, que jamais executa os códigos que traduz durante seu processo, não sabe que a condição é verdadeira e que a variável primitiva "j" sempre será inicializada. Desta forma, ao tentar rodar o código, aparecerá um erro de compilação: "error: variable j might not have been initialized".&lt;/p&gt;

&lt;h2&gt;
  
  
  Endereços de memória
&lt;/h2&gt;

&lt;p&gt;O segundo tipo de dado em Java é chamado de &lt;strong&gt;referência&lt;/strong&gt;. Essas variáveis armazenam uma referência, ou seja, o endereço de memória de um objeto, em vez de armazenar o seu valor diretamente, como ocorre com os tipos primitivos. Esse armazenamento ocorre na memória Heap.&lt;/p&gt;

&lt;p&gt;Os tipos referências são classes, interfaces, enums e objetos, de maneira geral. &lt;/p&gt;

&lt;p&gt;Aqui, um adendo. A String que usamos amplamente nos nossos códigos é uma classe, e não um tipo primitivo. Note que até o nome vem em letra maiúscula, como é convenção de nomenclatura das classes em Java.&lt;/p&gt;

&lt;p&gt;A String possui, inclusive, métodos, como o length(), que retorna o tamanho do texto armazenado nela, o charAt(int index), que retorna o índice de um caractere no texto, ou substring(int beginIndex, int endIndex), que retorna um pedaço de uma string.&lt;/p&gt;

&lt;p&gt;Mas, se você quiser facilitar a manipulação de dados primitivos, o Java também permite. Para isso, ele possui a classe Wrapper, que já vem com uma série de métodos built-in para trabalhar com os tipos básicos.&lt;/p&gt;

&lt;p&gt;Os Wrappers, basicamente, trazem o mesmo nome da variável primitiva, porém, com a primeira letra maiúscula:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Byte para byte&lt;/li&gt;
&lt;li&gt;Short para short&lt;/li&gt;
&lt;li&gt;Integer para int&lt;/li&gt;
&lt;li&gt;Long para long&lt;/li&gt;
&lt;li&gt;Float para float&lt;/li&gt;
&lt;li&gt;Double para double&lt;/li&gt;
&lt;li&gt;Character para char&lt;/li&gt;
&lt;li&gt;Boolean para boolean
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class WrapperExample {
    public static void main(String[] args) {
        String numeroStr = "123";
        Integer num1 = Integer.parseInt(numeroStr);
        Integer num2 = 200;

        int resultadoComparacao = Integer.compare(num1, num2);

        if (resultadoComparacao &amp;lt; 0) {
            System.out.println(num1 + " é menor que " + num2);
        } else if (resultadoComparacao &amp;gt; 0) {
            System.out.println(num1 + " é maior que " + num2);
        } else {
            System.out.println(num1 + " é igual a " + num2);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse código de exemplo, utiliza-se o Wrapper de int para converter uma string em número (Integer.parse) e depois compará-lo com outro número (Integer.compare).&lt;/p&gt;

&lt;p&gt;A String, contudo, tem uma particularidade que outras classes não possuem. Ela é imutável.&lt;/p&gt;

&lt;p&gt;Vamos refletir por meio deste exemplo básico:&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 Main {
  public static void main(String[] args) {

    String text1 = "Hello";
    String text2 = text1;

    System.out.println(text1); //output: Hello
    System.out.println(text2); //output: Hello

    text1 = "Weird";
    System.out.println(text1); //output: Weird
    System.out.println(text2); //output: Hello

    text2 = "World";
    System.out.println(text1); //output: Weird
    System.out.println(text2); //output: World

    TestClass test1 = new TestClass("propertyValue");
    TestClass test2 = test1;

    System.out.println(test1.getProperty()); //output: propertyValue
    System.out.println(test2.getProperty()); //output: propertyValue

    test2.setProperty("newValue");

    System.out.println(test1.getProperty()); //output: newValue
    System.out.println(test2.getProperty()); //output: newValue   
  }

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

&lt;/div&gt;



&lt;p&gt;Neste caso, note que, por mais que a String "text2" aponte para "text1", mudanças em "text2" não refletiram mudanças em "text1". Agora, quando o Objeto "test2", que apontava para "test1" teve uma propriedade alterada, essa alteração foi sim refletiva em "test1" também.&lt;/p&gt;

&lt;p&gt;Ué, mas as variáveis de referência não armazenam endereços de memória, em vez de valores literais? Sim. Armazenam. O que acontece é que os desenvolvedores da linguagem Java tomaram a decisão de deixar variáveis do tipo String imutáveis. Isso significa que, uma vez definido, o valor de um objeto String não pode ser alterado de maneira indireta por outro objeto.&lt;/p&gt;

&lt;p&gt;No exemplo, portanto, não estamos alterando o valor do objeto que text1 referenciava anteriormente (já que String é imutável). Em vez disso, estamos criando um novo objeto String com o valor "Weird" e fazendo text1 apontar para esse novo objeto. Já text2 ainda apontará para o objeto original "Hello" e é por isso que ele mantém o valor "Hello".&lt;/p&gt;

&lt;p&gt;Em suma, atribuir um novo valor a uma string não modifica o valor do objeto existente, apenas muda a referência para um novo objeto.&lt;/p&gt;

&lt;p&gt;Já os objetos de classes customizadas, como TestClass, são mutáveis. Ambas as referências test1 e test2 apontam para o mesmo objeto, então alterar o estado de uma delas reflete na outra.&lt;/p&gt;

</description>
      <category>java</category>
      <category>tiposdedados</category>
      <category>variaveis</category>
      <category>memoria</category>
    </item>
    <item>
      <title>Heap vs Stack: como o Java gerencia o que deve ser lembrado ou esquecido</title>
      <dc:creator>Ana Carolina Cortez</dc:creator>
      <pubDate>Sat, 07 Sep 2024 18:44:56 +0000</pubDate>
      <link>https://dev.to/anaccortez/heap-vs-stack-como-o-java-gerencia-o-que-deve-ser-lembrado-ou-esquecido-3ndm</link>
      <guid>https://dev.to/anaccortez/heap-vs-stack-como-o-java-gerencia-o-que-deve-ser-lembrado-ou-esquecido-3ndm</guid>
      <description>&lt;p&gt;Quando executamos um programa, o sistema operacional aloca memória para que essa aplicação possa armazenar dados e recuperá-los pelo tempo que for necessário. Diferentemente de C ou C++, em que o programador tem a liberdade de fazer a alocação de memória e gerenciar ponteiros "na mão", em Java quem faz a gestão dos armazenamentos voláteis é a JVM (Java Virtual Machine), abstraindo essa complexidade para nós em dois sistemas de alocação, a Heap e a Stack.&lt;/p&gt;

&lt;p&gt;A diferença entre elas está no objetivo do armazenamento e na necessidade (ou não) de compartilhar aquele dado com múltiplos processos.&lt;/p&gt;

&lt;p&gt;A JVM utiliza a &lt;strong&gt;Stack para dados de curto prazo&lt;/strong&gt; e segue uma estrutura LIFO (Last In First Out - último a chegar, primeiro a sair). A Stack é uma área de memória utilizada para gerenciar a execução de métodos, armazenar variáveis locais e chamadas de método de forma organizada em frames. Cada thread na JVM tem sua própria stack. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Já a Heap é uma área de memória global&lt;/strong&gt; compartilhada entre todas as threads, onde são alocados objetos e variáveis que precisam ter uma vida útil além do escopo do método que os criou. &lt;/p&gt;

&lt;p&gt;A memória na Heap é gerenciada pelo Garbage Collector, que remove objetos não referenciados para liberar espaço, sendo usada para dados de longo prazo.&lt;/p&gt;

&lt;p&gt;Vamos usar um exemplo prático. &lt;/p&gt;

&lt;p&gt;Quando uma variável primitiva é criada no escopo de um método, ela deve ficar disponível para uso enquanto o método for executado. Desta forma, é a Stack quem guardará essa variável, pois ela é responsável pelo ciclo de vida dos dados que possuem uma utilidade única e específica no programa.&lt;/p&gt;

&lt;p&gt;Porém, quando um método cria uma instância, esse objeto poderá ser utilizado em outros trechos do programa, e não apenas onde foi declarado. Isso acontece claramente quando criamos um objeto que representa um registro no banco de dados. No nosso programa, essa mesma instância pode ser consultada, editada e removida ao longo de uma execução. Desta forma, quem cuidará do armazenamento do objeto será a Heap.&lt;/p&gt;

&lt;p&gt;Para ilustrar essa questão, vou utilizar um exemplo simples que o autor Hanumant Deshmukh descreve em seu guia "OCP Java SE 17/21 Programmer Exam Fundamentals". Esse livro, aliás, é maravilhoso, pois consegue ser bem didático na explicação de processos bastante complexos. Super recomendo se você, como eu, está em busca da certificação Oracle Certified Professional (OCP). O autor usa uma instância de String para fins didáticos, mas vou usar um objeto customizado aqui só para não correr o risco de burlar direitos autorais (:S)&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 Main {
    public static void main(String[] args) {
        HeapObj heapObject = newObject();
        int counter = 0;

        while (counter++ &amp;lt; 10){
            print(heapObject.getName());
        }
    }

    public static HeapObj newObject(){
        return new HeapObj("Happy instance");
    }

    public static void print(String text){
        System.out.println(text);
    }
}

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

&lt;/div&gt;



&lt;p&gt;No exemplo, a classe Main chama três métodos: o principal (main), um que cria a instância do objeto HeapObj, e outro que apenas imprime um texto. &lt;/p&gt;

&lt;p&gt;Se tirássemos uma fotografia quando todos os métodos já foram chamados, a Stack e a Heap estariam assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdapya71hcok9fywzh26d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdapya71hcok9fywzh26d.png" alt=" " width="455" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ou seja:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Na inicialização:
&lt;/h3&gt;

&lt;p&gt;Stack: main frame (contém args, heapObject, counter).&lt;br&gt;
Heap: Vazia.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Após newObject:
&lt;/h3&gt;

&lt;p&gt;Stack: main frame (contém args, heapObject referência, counter).&lt;br&gt;
Heap: Um objeto HeapObj com a string "Happy instance".&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Durante o Loop:
&lt;/h3&gt;

&lt;p&gt;Stack: main frame (contém args, heapObject referência, counter), múltiplos frames print que são empilhados e desempilhados.&lt;br&gt;
Heap: O mesmo objeto HeapObj e a string "Happy instance".&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Após o loop:
&lt;/h3&gt;

&lt;p&gt;Stack: main frame (contém args, heapObject referência).&lt;br&gt;
Heap: O mesmo objeto HeapObj e a string "Happy instance".&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Ao final do programa:
&lt;/h3&gt;

&lt;p&gt;Stack: vazia.&lt;br&gt;
Heap: vazia.&lt;/p&gt;

</description>
      <category>java</category>
      <category>stack</category>
      <category>heap</category>
      <category>garbagecollector</category>
    </item>
  </channel>
</rss>
