image

Bootcamps ilimitados e +750 cursos pra sempre

70
%OFF
Article image
Arthur Haerdy
Arthur Haerdy28/08/2026 18:01
Compartilhe
IBM Bob: IA de Nível Empresarial para Desenvolvedores e Tech LeadersRecomendados para vocêIBM Bob: IA de Nível Empresarial para Desenvolvedores e Tech Leaders

Roadmap Java - Parte 8: Arrays e Loops

  • #Java

Este é o oitavo artigo da série Roadmap Java. Recapitulando rapidamente: nas Partes 1 e 2, demos os primeiros passos e montamos o ambiente de desenvolvimento; nas Partes 3, 4 e 5, conhecemos variáveis, tipos, operadores e String; na Parte 6, vimos entrada e saída de dados com Scanner; e na Parte 7, aprendemos a tomar decisões com estruturas condicionais e switch-case, além de conhecer escopo de variável e valores padrão.

Com isso, já temos praticamente todo o vocabulário básico da linguagem: variáveis, tipos, operadores, entrada e saída, e controle de fluxo. Mas até aqui, cada variável só guardava um único valor por vez, e cada linha de código só rodava uma única vez. Chegou a hora de resolver as duas coisas. Neste artigo, nós vamos:

  • entender o que são Arrays e como criar, acessar e imprimir um;
  • aprender a ordenar um Array;
  • aprender a fazer busca binária em um Array já ordenado;
  • aprender a preencher um Array com um valor fixo;
  • entender por que copiar um Array com = não funciona como se espera, e como copiar de fato;
  • aprender a comparar o conteúdo de dois Arrays corretamente;
  • conhecer os quatro tipos de loop em Java: for, for-each, while e do-while.

Como trabalhar com Arrays em Java

Um Array é uma estrutura de dados que guarda múltiplos valores do mesmo tipo, em posições sequenciais de memória. É a primeira estrutura que vamos ver capaz de superar a limitação de "uma variável, um valor" que carregamos desde a Parte 3.

public class Main {
  public static void main(String[] args) {
      char vogais[] = new char[5];
  }
}

Para declarar um Array, você escreve o tipo do dado, o nome do array seguido de um par de colchetes (indicando que se trata de um array), o operador de atribuição, a palavra-chave new, o tipo novamente e o tamanho do array entre colchetes. No exemplo acima, vogais vai guardar exatamente 5 caracteres, nem mais, nem menos: o tamanho de um array, uma vez definido, não muda.

Os índices de um array em Java começam em 0 (dizemos que são zero-based). Para acessar ou atribuir um elemento específico, usamos o nome do array seguido do índice entre colchetes:

public class Main {
  public static void main(String[] args) {
      char vogais[] = new char[5];

      vogais[0] = 'a';
      vogais[1] = 'e';
      vogais[2] = 'i';
      vogais[3] = 'o';
      vogais[4] = 'u';
  }
}

Como os índices vão de 0 até tamanho - 1, um array de 5 posições tem índices válidos de 0 a 4. Tentar acessar vogais[5] compila normalmente, mas gera um erro em tempo de execução, chamado ArrayIndexOutOfBoundsException: um lembrete de que o compilador não consegue prever, sozinho, todo índice inválido que o seu programa possa vir a usar.

Diferente do que fizemos linha a linha acima, também é possível declarar e já inicializar um array completo em uma única instrução, usando chaves no lugar de new:

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      char vogais[] = {'a', 'e', 'i', 'o', 'u'};

      System.out.println("Estas são as vogais: " + Arrays.toString(vogais));
  }
}

Repare no uso de Arrays.toString(): um array, assim como vimos com outros tipos de referência, não produz uma saída legível se você simplesmente passar ele direto para System.out.println(). Arrays.toString() resolve isso, formatando o conteúdo do array como uma string legível, entre colchetes.

Para descobrir quantas posições um array tem, use a propriedade length (sem parênteses, já que não é um método): vogais.length retorna 5.

Arrays também podem ser multidimensionais, úteis, por exemplo, para representar dados organizados em forma de tabela, com linhas e colunas:

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      int rotinaRemedios[][] = {
              {1, 2, 3, 4, 5, 6, 7},
              {0, 1, 1, 0, 1, 1, 0},
              {1, 0, 1, 0, 1, 0, 0},
              {0, 0, 1, 1, 0, 1, 0},
      };

      System.out.println(Arrays.deepToString(rotinaRemedios));
  }
}

Para arrays multidimensionais, use Arrays.deepToString() em vez de Arrays.toString(): do contrário, cada linha interna é impressa como um endereço de memória, em vez de seu conteúdo. Para acessar um único valor dentro de um array multidimensional, você precisa de dois índices: rotinaRemedios[2][3] acessa a linha de índice 2, coluna de índice 3.

A classe java.util.Arrays, que já apareceu em todos os exemplos acima, reúne diversos métodos utilitários prontos para trabalhar com arrays. Vamos conhecer os mais usados no dia a dia a seguir.

Como ordenar um Array

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      char vogais[] = {'e', 'u', 'o', 'i', 'a'};

      Arrays.sort(vogais);

      System.out.println("Array ordenado: " + Arrays.toString(vogais)); // [a, e, i, o, u]
  }
}

Arrays.sort() ordena o array no próprio local (in place), ou seja, não devolve um novo array; ele modifica diretamente o array original. Também é possível passar um índice de início e um de fim, para ordenar apenas uma parte do array, deixando o restante como estava.

Vale entender, por cima, o que acontece por trás desse método, porque isso explica uma escolha interessante do próprio Java: para tipos primitivos (como o char do exemplo, ou int, double etc.), Arrays.sort() usa uma variação do Dual-Pivot Quicksort, que tem desempenho médio muito bom, mas não garante ordem de execução previsível para elementos "iguais" (não que isso importe muito para primitivos, já que dois int iguais são indistinguíveis entre si). Já para arrays de objetos (como um array de String), o método muda de estratégia internamente e passa a usar uma variação do TimSort, um algoritmo estável, ou seja, que preserva a ordem relativa de elementos considerados equivalentes pela comparação usada. Essa diferença de comportamento entre primitivos e objetos é decidida automaticamente pelo próprio Arrays.sort(), sem que você precise escolher nada: basta saber que ela existe, caso um dia a ordem entre elementos "empatados" faça diferença no seu programa.

Como fazer busca binária em um Array

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      char vogais[] = {'a', 'e', 'i', 'o', 'u'};

      char chave = 'i';

      int indiceEncontrado = Arrays.binarySearch(vogais, chave);

      System.out.println("A vogal 'i' está no índice: " + indiceEncontrado); // 2
  }
}

Arrays.binarySearch() procura um valor dentro do array e devolve o índice em que ele foi encontrado. A condição para isso funcionar corretamente é que o array já esteja ordenado em ordem crescente: se não estiver, o resultado não é confiável, e a solução é ordenar primeiro com Arrays.sort(), como vimos na seção anterior. Se o valor procurado não for encontrado, o método devolve um índice negativo.

Vale entender por que a busca binária existe, além de simplesmente chamar Arrays.binarySearch(): percorrer um array do início ao fim, comparando elemento por elemento até achar o que se procura (a chamada busca linear), é um algoritmo simples, mas que, no pior caso, pode exigir percorrer o array inteiro. A busca binária é bem mais eficiente: a cada tentativa, ela olha para o elemento bem no meio do intervalo de busca e decide, com uma única comparação, para qual metade do array (esquerda ou direita) o valor procurado deve estar, descartando a outra metade por completo. Repetindo esse processo, o intervalo de busca é reduzido pela metade a cada tentativa, até restar um único candidato. É exatamente esse ganho de eficiência que exige, como contrapartida, que o array esteja ordenado: sem ordem, não existe "metade certa" para descartar.

Como preencher um Array

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      char vogais[] = {'e', 'u', 'o', 'i', 'a'};

      Arrays.fill(vogais, 'x');

      System.out.println("Array preenchido: " + Arrays.toString(vogais)); // [x, x, x, x, x]
  }
}

Arrays.fill() substitui todas as posições do array por um único valor, também operando no próprio array. Assim como Arrays.sort(), ele também aceita índices opcionais de início e fim, caso você queira preencher apenas uma parte do array.

Como copiar um Array

Aqui vale um lembrete direto do que já vimos sobre String na Parte 5: arrays também são tipos de REFERÊNCIA. Isso significa que "copiar" um array usando o operador = não cria uma cópia de fato: cria uma segunda variável apontando para o mesmo array na memória:

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      int numerosImpares[] = {1, 3, 5};
      int copiaNumeros[] = numerosImpares;

      Arrays.fill(numerosImpares, 0);

      System.out.println("Cópia: " + Arrays.toString(copiaNumeros)); // [0, 0, 0] (também mudou)
  }
}

Repare que alterar numerosImpares também alterou copiaNumeros, mesmo sem tocarmos diretamente em copiaNumeros, porque, na prática, as duas variáveis sempre apontaram para o mesmo array. Para copiar de fato, criando um array novo e independente, use Arrays.copyOf():

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      int numerosImpares[] = {1, 3, 5};
      int copiaNumeros[] = Arrays.copyOf(numerosImpares, numerosImpares.length);

      Arrays.fill(numerosImpares, 0);

      System.out.println("Cópia: " + Arrays.toString(copiaNumeros)); // [1, 3, 5] (preservada)
  }
}

Agora sim, alterar numerosImpares não afeta copiaNumeros, já que são dois arrays distintos na memória. Existe também Arrays.copyOfRange(), para copiar apenas um trecho do array original, especificando um índice inicial e um final (o índice final, nesse caso, não é incluído na cópia).

Um detalhe que vale adiantar, mesmo sem ainda termos falado sobre classes e objetos em profundidade: Arrays.copyOf() resolve completamente o problema quando o array guarda tipos primitivos, como no exemplo acima, porque cada posição do novo array recebe uma cópia independente do valor. Mas, em um array de tipos de referência (um array de String, por exemplo, ou, mais adiante na série, um array de objetos criados por você), o que cada posição guarda não é o dado em si, e sim uma referência para onde o dado está na memória. Arrays.copyOf() cria um novo array e copia essas referências, mas não duplica o que cada referência aponta. Isso é chamado de CÓPIA RASA (shallow copy): os dois arrays passam a ser independentes entre si, mas continuam apontando para os mesmos objetos internos. Duplicar de fato também o conteúdo apontado por cada referência (uma cópia profunda, ou deep copy) exige mais trabalho, e vamos retomar esse assunto quando chegarmos ao tópico de classes e objetos, mais adiante nesta série.

Como comparar dois Arrays

Seguindo o mesmo raciocínio da seção anterior: como arrays são tipos de referência, usar == para comparar dois arrays compara se são exatamente o mesmo objeto na memória, não se o conteúdo é igual:

public class Main {
  public static void main(String[] args) {
      int a[] = {1, 3, 5, 7, 9};
      int b[] = {1, 3, 5, 7, 9};

      System.out.println(a == b); // false, mesmo com o mesmo conteúdo
  }
}

Para comparar o conteúdo de dois arrays de fato, use Arrays.equals():

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
      int a[] = {1, 3, 5, 7, 9};
      int b[] = {1, 3, 5, 7, 9};

      System.out.println(Arrays.equals(a, b)); // true
  }
}

Para arrays multidimensionais, o equivalente é Arrays.deepEquals(), assim como Arrays.deepToString() foi o equivalente de Arrays.toString() para exibição.

Como usar Loops em Java

Loops (ou laços de repetição) repetem um bloco de código um determinado número de vezes, ou até que uma condição deixe de ser atendida. Eles resolvem exatamente a segunda limitação que mencionamos no início do artigo: até aqui, cada linha do nosso código rodava uma única vez, de cima para baixo. Com loops, isso muda.

Em Java, existem três formas principais de escrever um loop: for, for-each e while, sendo que while ainda tem uma variação, o do-while.

For

O loop for é o mais usado quando você já sabe, de antemão, quantas vezes (ou sob qual condição) a repetição deve acontecer. Ele é composto por três partes, separadas por ponto e vírgula, dentro dos parênteses: inicialização, condição e expressão de atualização.

public class Main {
  public static void main(String[] args) {
      for (int numero = 0; numero <= 10; numero++) {
          System.out.println(numero);
      }
  }
}

O que acontece, passo a passo:

  1. int numero = 0: a variável de controle é inicializada, uma única vez, antes da primeira repetição.
  2. numero <= 10: a condição é verificada antes de cada repetição.
  3. Se a condição for verdadeira, o bloco de código é executado.
  4. numero++: a variável de controle é atualizada (nesse caso, usando o operador de incremento que já conhecemos da Parte 4).
  5. O programa volta ao passo 2, repetindo o ciclo até que a condição se torne falsa.

Um uso muito comum do for é percorrer um array, usando a variável de controle como índice:

public class Main {
  public static void main(String[] args) {
      int fibonacci[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55};

      for (int i = 0; i < fibonacci.length; i++) {
          System.out.println(fibonacci[i]);
      }
  }
}

Repare que a condição usa fibonacci.length em vez de um número fixo: assim, o loop continua funcionando corretamente mesmo que o tamanho do array mude.

Loops também podem ser aninhados, ou seja, um loop colocado dentro de outro. Um exemplo clássico é imprimir a tabuada de vários números de uma vez:

public class Main {
  public static void main(String[] args) {
      for (int numero = 1; numero <= 10; numero++) {
          System.out.println(String.format("%ntabuada do %d", numero));

          for (int multiplicador = 1; multiplicador <= 10; multiplicador++) {
              System.out.println(String.format("%d x %d = %d", numero, multiplicador, numero * multiplicador));
          }
      }
  }
}

Para cada valor de numero no loop externo, o loop interno roda por completo, do início ao fim, antes que o loop externo avance para o próximo número.

For-Each

Quando o seu objetivo é simplesmente percorrer todos os elementos de um array (ou de outra coleção, como veremos mais adiante na série), sem se preocupar com o índice de cada um, o for-each é uma forma mais enxuta e legível de escrever o mesmo loop:

public class Main {
  public static void main(String[] args) {
      int fibonacci[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55};

      for (int numero : fibonacci) {
          System.out.println(numero);
      }
  }
}

A leitura é praticamente literal: "para cada numero dentro de fibonacci". O tipo declarado no início do loop (int, nesse caso) precisa ser compatível com o tipo dos elementos guardados na coleção percorrida. Em troca dessa simplicidade, o for-each abre mão do acesso direto ao índice de cada elemento: se você precisar dele, o for tradicional continua sendo a opção certa.

Existe também uma pegadinha específica do for-each que vale a pena conhecer de antemão. A variável usada dentro do loop (numero, no exemplo acima) é, para tipos primitivos, uma cópia do valor de cada posição do array, não uma referência à posição em si. Isso significa que alterar essa variável dentro do loop não altera o array original:

public class Main {
  public static void main(String[] args) {
      int numeros[] = {1, 2, 3};

      for (int numero : numeros) {
          numero = numero * 10;
      }

      System.out.println(numeros[0]); // 1, e não 10
  }
}

Mesmo multiplicando numero por 10 a cada repetição, o array numeros continua exatamente como era antes do loop começar. Para modificar de fato os elementos de um array durante a repetição, é preciso usar o for tradicional, atribuindo o novo valor diretamente à posição do array através do índice (numeros[i] = numeros[i] * 10, por exemplo), e não apenas à variável de controle do loop.

While

Use while quando você quiser repetir um bloco de código enquanto uma condição continuar verdadeira, sem depender de uma etapa fixa de inicialização e atualização já embutida na sintaxe do loop, como acontece no for:

public class Main {
  public static void main(String[] args) {
      int numero = 5;
      int multiplicador = 1;

      while (multiplicador <= 10) {
          System.out.println(String.format("%d x %d = %d", numero, multiplicador, numero * multiplicador));

          multiplicador++;
      }
  }
}

Aqui, a inicialização (int multiplicador = 1) acontece antes do loop começar, e a atualização (multiplicador++) precisa ser escrita manualmente, dentro do próprio bloco. A condição é verificada antes de cada repetição, exatamente como no for, mas, diferente dele, não existe um lugar fixo e obrigatório para inicialização e atualização: cabe a quem escreve o código organizar isso, o que dá mais flexibilidade em cenários onde o número de repetições não é conhecido de antemão.

Do-While

O do-while é uma variação do while que inverte a ordem de verificação: primeiro o bloco de código é executado, e só depois a condição é verificada. Na prática, isso garante que o bloco rode pelo menos uma vez, mesmo que a condição já comece falsa.

public class Main {
  public static void main(String[] args) {
      int numero = 5;
      int multiplicador = 1;

      do {
          System.out.println(String.format("%d x %d = %d", numero, multiplicador, numero * multiplicador));

          multiplicador++;
      } while (multiplicador <= 10);
  }
}

Repare na sintaxe: o bloco de código vem primeiro, entre do { }, e a condição só aparece depois, junto ao while, terminando com ponto e vírgula.

O do-while é especialmente útil em situações em que você precisa executar algo pelo menos uma vez antes mesmo de checar se deve continuar. O exemplo mais comum é exibir um menu de opções repetidamente, até que o usuário digite a opção de sair: o menu precisa aparecer ao menos uma vez, mesmo antes de qualquer entrada do usuário ser avaliada.

Como interromper ou pular uma repetição: break e continue

Os quatro loops que vimos até aqui controlam sua própria repetição através da condição declarada em cada um. Mas, às vezes, é preciso alterar esse fluxo de dentro do próprio bloco, com base em alguma verificação que só faz sentido em uma repetição específica. Para isso, Java oferece duas palavras-chave: break e continue.

Você já conhece break do artigo anterior desta série, quando ele foi usado para encerrar cada bloco de um switch-case. Dentro de um loop, o efeito é semelhante: break interrompe o loop imediatamente, mesmo que a condição de repetição ainda fosse verdadeira, e o programa segue para a primeira linha depois do loop.

public class Main {
  public static void main(String[] args) {
      int numeros[] = {4, 8, 15, 16, 23, 42};

      for (int numero : numeros) {
          if (numero > 20) {
              break;
          }

          System.out.println(numero);
      }
  }
}

Nesse exemplo, o loop imprime 4, 8, 15 e 16, e para assim que encontra 23, sem chegar a avaliar 42. break é especialmente útil quando você está procurando um valor específico dentro de um array e quer parar assim que ele for encontrado, em vez de continuar percorrendo o restante sem necessidade.

continue tem um efeito mais sutil: ele não encerra o loop, apenas pula o restante do bloco de código na repetição atual, indo direto para a próxima verificação da condição (ou, no caso do for, para a expressão de atualização).

public class Main {
  public static void main(String[] args) {
      int numeros[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

      for (int numero : numeros) {
          if (numero % 2 != 0) {
              continue;
          }

          System.out.println(numero);
      }
  }
}

Aqui, sempre que numero for ímpar, o System.out.println() daquela repetição é simplesmente pulado, e o loop segue direto para o próximo número. O resultado é a impressão apenas dos números pares: 2, 4, 6, 8 e 10.

Em loops aninhados, tanto break quanto continue afetam, por padrão, apenas o loop mais interno em que estão escritos, deixando os loops externos intactos.

O que vem a seguir

Neste oitavo artigo, conhecemos os Arrays (como criar, acessar, ordenar, buscar, preencher, copiar e comparar) e os quatro formatos de loop disponíveis em Java: for, for-each, while e do-while, além de break e continue para controlar a repetição de dentro do próprio loop. Com isso, já temos como guardar múltiplos valores em uma única estrutura e repetir ações sobre eles, dois blocos fundamentais para qualquer programa um pouco mais elaborado.

Arrays, porém, têm uma limitação importante que ficou evidente ao longo deste artigo: o tamanho é fixo, definido no momento da criação, e não muda depois. Na Parte 9 desta série, vamos conhecer a ArrayList, uma alternativa de tamanho dinâmico, com o tópico "Como trabalhar com ArrayList em Java", cobrindo adição, remoção, clonagem, comparação, ordenação e outras operações comuns sobre listas.

Até lá!

Este artigo é parte do Roadmap Java, uma série de introdução a Java escrita do zero, com progressão didática própria pensada para quem nunca programou na linguagem antes.

Artigos dessa série na DIO:

Compartilhe
Recomendados para você
CI&T - Java AI Copilot
Itaú - Java com Inteligência Artificial
Bootcamp NTT DATA: Backend Java com Spring AI
Comentários (1)
Arthur Haerdy
Arthur Haerdy - 28/08/2026 18:07

Fico feliz em compartilhar mais essa parte da série!


Mesmo com o Roadmap ainda na etapa de fundamentos, resolvi trazer neste artigo alguns conceitos um pouco mais aprofundados sobre Arrays, como o algoritmo usado internamente pelo Arrays.sort() (Dual-Pivot Quicksort para primitivos e TimSort para objetos), a lógica por trás da busca binária e por que ela exige um array ordenado, e a diferença entre cópia rasa e cópia profunda ao copiar arrays de tipos de referência.


A ideia é deixar essa base preparada agora, para que faça mais sentido quando a chegarmos em Coleções e Objetos mais adiante na série.


Dúvidas e sugestões são bem-vindas nos comentários.


Abraços!

Recomendados para vocêIBM Bob: IA de Nível Empresarial para Desenvolvedores e Tech Leaders