Java A Classe Arrays
Na aula Percorrer Arrays você escreveu laços para somar, buscar e inverter. Muitas tarefas com arrays são tão comuns que o Java já traz uma caixa de ferramentas pronta: a classe Arrays. Com uma linha, ela ordena, copia, preenche, compara e procura. Nesta aula você conhece as ferramentas mais usadas, uma de cada vez.
- Como usar a classe
Arrays(oimporte o "Arrays." na frente). sort: ordenar números e textos (e por que "Érica" vai para o fim).toStringedeepToString: mostrar o conteúdo.fill: preencher tudo com um valor.copyOfecopyOfRange: copiar o array inteiro ou um pedaço.equals: comparar o conteúdo (e por que==não serve).binarySearch: a busca rápida, que exige o array ordenado.asListestream: as pontes para as listas e para as streams.
Os exemplos rodam no terminal da Ana (máquina fictícia notebook, pasta ~/java, JDK 25) com java Main.java.
A ideia antes do código
Você poderia cortar madeira com uma faca de cozinha, mas uma serra faz melhor, mais rápido e sem se machucar. A classe Arrays é a caixa de ferramentas dos arrays: cada ferramenta é um método (uma ação pronta, com nome; os métodos têm uma aula própria em Métodos) que você chama assim:
- Arrays
- O nome da classe, a "caixa". Com
Amaiúsculo esno fim. - .
- "De dentro de": pega uma ferramenta da caixa.
- sort
- O nome do método, a ferramenta: "ordenar".
- (notas)
- Entre parênteses, o array em que ela vai trabalhar.
A classe mora no pacote java.util (veja Pacotes e import), então todo arquivo que a usa começa com:
import java.util.Arrays;
Sem essa linha, o javac não sabe o que é Arrays e mostra error: cannot find symbol com symbol: variable Arrays (veja o exemplo real em Arrays).
Arrays ≠ array
"Um array" é o seu armário de valores (int[] notas). "Arrays" (com maiúscula) é a classe com as ferramentas. Você nunca cria um Arrays: só usa os métodos dela, passando o seu array.
sort: ordenar
Ordenar do menor para o maior, com uma linha:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
System.out.println("Antes: " + Arrays.toString(notas));
Arrays.sort(notas);
System.out.println("Depois: " + Arrays.toString(notas));
}
}
$ java Main.java Antes: [7, 9, 5, 10, 6] Depois: [5, 6, 7, 9, 10]
Repare: o sort não devolve um array novo. Ele arruma o próprio array, como quem arruma os livros na mesma prateleira. A ordem original se perde. Se você precisar dela, faça uma cópia antes (com copyOf, logo abaixo).
Missão: ordene os preços com Arrays.sort e mostre Mais barato: 5, mais caro: 30 usando o primeiro e o último elemento do array ordenado.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] precos = {30, 12, 5, 8, 21};
// ordene aqui
System.out.println("Mais barato: " + precos[0] + ", mais caro: " + precos[precos.length - 1]);
}
}
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] precos = {30, 12, 5, 8, 21};
Arrays.sort(precos);
System.out.println("Mais barato: " + precos[0] + ", mais caro: " + precos[precos.length - 1]);
}
}
Ordenar textos: maiúsculas e acentos
Com String, o sort usa a ordem dos códigos dos caracteres (a tabela Unicode, veja char e boolean), e não a ordem do dicionário. Isso dá resultados surpreendentes:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] nomes = {"bruno", "Davi", "Érica", "Ana", "carla", "Fábio"};
Arrays.sort(nomes);
System.out.println(Arrays.toString(nomes));
Arrays.sort(nomes, String.CASE_INSENSITIVE_ORDER);
System.out.println(Arrays.toString(nomes));
}
}
$ java Main.java [Ana, Davi, Fábio, bruno, carla, Érica] « maiúsculas primeiro; Érica no fim [Ana, bruno, carla, Davi, Fábio, Érica] « ignorando maiúsculas; Érica continua no fim
- Na tabela de códigos, todas as maiúsculas (A–Z) vêm antes de todas as minúsculas (a–z). Por isso "Fábio" ficou antes de "bruno".
- Letras acentuadas têm códigos maiores que qualquer letra sem acento. Por isso "Érica" foi para o fim.
String.CASE_INSENSITIVE_ORDER("ordem que ignora maiúsculas e minúsculas") é um segundo argumento que muda o critério. Resolveu as maiúsculas, mas não os acentos.
Para a ordem do dicionário em português, o Java tem o Collator ("agrupador"), que segue as regras do idioma do computador (na máquina da Ana, português do Brasil):
import java.text.Collator;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] nomes = {"bruno", "Davi", "Érica", "Ana", "carla", "Fábio"};
Arrays.sort(nomes, Collator.getInstance());
System.out.println(Arrays.toString(nomes));
}
}
$ java Main.java [Ana, bruno, carla, Davi, Érica, Fábio]
Esses "critérios de ordem" se chamam comparadores e têm uma aula no Nível 3: Comparable e Comparator. Lá você também aprende a ordenar do maior para o menor.
toString e deepToString: mostrar
Você já usou bastante: Arrays.toString(notas) devolve o texto [7, 9, 5, 10, 6]. Ele existe porque System.out.println(notas) mostra só o "crachá" do array ([I@1e9e725a), como explicado em Arrays. Para matrizes (int[][]), use Arrays.deepToString, que mostra todos os níveis (veja Arrays Multidimensionais).
fill: preencher tudo com um valor
Um array novo de int vem cheio de zeros. Se você quer outro valor em todas as posições, o fill ("preencher") faz isso sem laço:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] presenca = new int[7];
Arrays.fill(presenca, 1);
System.out.println(Arrays.toString(presenca));
char[] linha = new char[10];
Arrays.fill(linha, '-');
System.out.println(linha);
}
}
$ java Main.java [1, 1, 1, 1, 1, 1, 1] ----------
- Arrays.fill
- A ferramenta "preencher".
- (presenca,
- Primeiro argumento: o array.
- 1)
- Segundo argumento: o valor que vai em todas as posições. Precisa ser do tipo do array.
(O println de um char[] é o único que mostra as letras juntas, sem colchetes; daí a linha de tracinhos.)
copyOf: copiar
Em Arrays você viu que int[] b = a; não copia: cria outro nome para o mesmo array. O copyOf cria um array novo, independente, e ainda deixa escolher o tamanho:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int[] copia = Arrays.copyOf(notas, notas.length);
int[] maior = Arrays.copyOf(notas, 8);
int[] menor = Arrays.copyOf(notas, 3);
copia[0] = 0;
System.out.println("notas: " + Arrays.toString(notas));
System.out.println("copia: " + Arrays.toString(copia));
System.out.println("maior: " + Arrays.toString(maior));
System.out.println("menor: " + Arrays.toString(menor));
}
}
$ java Main.java notas: [7, 9, 5, 10, 6] « o original não mudou copia: [0, 9, 5, 10, 6] « só a cópia recebeu o 0 maior: [7, 9, 5, 10, 6, 0, 0, 0] « as posições novas vêm com o valor padrão menor: [7, 9, 5] « o que não coube foi cortado
- Arrays.copyOf
- A ferramenta "cópia de".
- (notas,
- O array original.
- notas.length)
- O tamanho da cópia. Igual ao original: cópia exata. Maior: completa com o valor padrão. Menor: corta o final.
Como um array não muda de tamanho, "aumentar um array" no Java é sempre isto: criar um maior com copyOf e passar a usar o novo. Se você precisa disso o tempo todo, o ArrayList faz sozinho.
Ordenar sem perder a ordem original
Juntando copyOf e sort:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int[] ordenadas = Arrays.copyOf(notas, notas.length);
Arrays.sort(ordenadas);
System.out.println("Original: " + Arrays.toString(notas));
System.out.println("Ordenadas: " + Arrays.toString(ordenadas));
System.out.println("Menor: " + ordenadas[0] + ", maior: " + ordenadas[ordenadas.length - 1]);
}
}
$ java Main.java Original: [7, 9, 5, 10, 6] Ordenadas: [5, 6, 7, 9, 10] Menor: 5, maior: 10
copyOfRange: copiar um pedaço
Para pegar só uma parte, diga onde começa e onde termina:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] semana = {"dom", "seg", "ter", "qua", "qui", "sex", "sáb"};
String[] uteis = Arrays.copyOfRange(semana, 1, 6);
System.out.println(Arrays.toString(uteis));
}
}
$ java Main.java [seg, ter, qua, qui, sex]
- Arrays.copyOfRange
- "Cópia de um intervalo".
- (semana,
- O array original.
- 1,
- O índice onde a cópia começa (incluído):
"seg". - 6)
- O índice onde ela para, sem incluir: o 6 é
"sáb", que fica de fora.
"Começo incluído, fim excluído" é uma regra que se repete em todo o Java (o substring das Strings é igual). A vantagem: o tamanho do pedaço é sempre fim - início (6 - 1 = 5 dias).
equals: comparar o conteúdo
Dois arrays com os mesmos valores são "iguais"? Depende de como você pergunta:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {7, 9, 5};
int[] b = {7, 9, 5};
int[] c = a;
System.out.println("a == b: " + (a == b));
System.out.println("a == c: " + (a == c));
System.out.println("Arrays.equals(a, b): " + Arrays.equals(a, b));
System.out.println("a.equals(b): " + a.equals(b));
}
}
$ java Main.java a == b: false « dois armários diferentes (com o mesmo conteúdo) a == c: true « o mesmo armário, com dois nomes Arrays.equals(a, b): true « mesmo tamanho e mesmos valores, na mesma ordem a.equals(b): false « parece certo, mas compara como o ==
| Comparação | Pergunta que ela faz | Use para |
|---|---|---|
a == b | "São o mesmo array?" | Quase nunca, com arrays. |
a.equals(b) | A mesma coisa que ==, para arrays | Nunca, com arrays: é uma armadilha. |
Arrays.equals(a, b) | "Têm o mesmo conteúdo?" | Comparar arrays comuns. |
Arrays.deepEquals(a, b) | Mesmo conteúdo, em todos os níveis | Comparar matrizes (int[][]). |
Com matrizes, o Arrays.equals compara as linhas como "crachás" e dá false mesmo com conteúdo igual; use Arrays.deepEquals, que deu true no laboratório para {{1, 2}, {3, 4}} × {{1, 2}, {3, 4}}. A mesma história do == × equals acontece com as Strings (veja Strings) e com objetos em geral (A Classe Object).
binarySearch: a busca rápida
A busca da aula Percorrer Arrays olha um elemento por vez. Num array ordenado há um jeito muito mais rápido, o mesmo que você usa num dicionário de papel: abre no meio; se a palavra vem antes, descarta a metade de trás; abre no meio do que sobrou… A cada passo, metade do trabalho some. É a busca binária ("binária" porque divide em dois):
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {5, 6, 7, 9, 10};
System.out.println("Posição do 9: " + Arrays.binarySearch(notas, 9));
System.out.println("Posição do 5: " + Arrays.binarySearch(notas, 5));
System.out.println("Posição do 8: " + Arrays.binarySearch(notas, 8));
}
}
$ java Main.java Posição do 9: 3 Posição do 5: 0 Posição do 8: -4 « negativo = não encontrado
- Se acha, devolve o índice.
- Se não acha, devolve um número negativo. Basta testar
< 0. (O número exato diz onde o valor deveria entrar:-(posição) - 1. O 8 entraria no índice 3, então-3 - 1 = -4.)
Num array fora de ordem, o binarySearch não dá erro: dá respostas erradas. Com {7, 9, 5, 10, 6}, no laboratório:
$ java Main.java Sem ordenar, posição do 9: -4 « o 9 está no índice 1, mas ele "não achou" Sem ordenar, posição do 5: 2 « este acertou por sorte
Chame Arrays.sort antes, sempre.
asList: o array visto como lista
O Java tem, além dos arrays, as listas (List), que têm muitos métodos prontos, como contains ("contém") e indexOf ("posição de"). O Arrays.asList mostra um array como se fosse uma lista:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
String[] frutas = {"maçã", "banana", "uva"};
List<String> lista = Arrays.asList(frutas);
System.out.println(lista);
System.out.println("Tem uva? " + lista.contains("uva"));
System.out.println("Posição da banana: " + lista.indexOf("banana"));
lista.set(0, "pera");
System.out.println(lista);
System.out.println(Arrays.toString(frutas));
lista.add("kiwi");
}
}
$ java Main.java [maçã, banana, uva] « uma lista se mostra sozinha, sem toString Tem uva? true Posição da banana: 1 [pera, banana, uva] [pera, banana, uva] « mudar a lista mudou o array: é o mesmo armário Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.AbstractList.add(AbstractList.java:155) at java.base/java.util.AbstractList.add(AbstractList.java:113) at Main.main(Main.java:14)
A lista do asList é uma "janela" sobre o array: dá para ler e trocar elementos (set), mas não dá para aumentar ou diminuir, porque o array por trás tem tamanho fixo. O add terminou em UnsupportedOperationException ("operação não suportada"). Para uma lista de verdade, que cresce, faça new ArrayList<>(Arrays.asList(frutas)). As listas são assunto de ArrayList, no Nível 3.
stream: só a ideia
Uma última ferramenta, só para você saber que existe. Arrays.stream(notas) transforma o array numa stream ("fluxo"): uma esteira por onde os valores passam e onde você encaixa operações prontas, como somar ou achar o maior:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int soma = Arrays.stream(notas).sum();
int maior = Arrays.stream(notas).max().getAsInt();
double media = Arrays.stream(notas).average().getAsDouble();
System.out.println("Soma: " + soma);
System.out.println("Maior: " + maior);
System.out.println("Média: " + media);
}
}
$ java Main.java Soma: 37 Maior: 10 Média: 7.4
O mesmo resultado dos laços da aula Percorrer Arrays, em uma linha cada. O getAsInt() e o getAsDouble() existem porque um array vazio não tem maior nem média; isso é explicado em Optional. Streams são uma das partes mais poderosas do Java moderno e têm aula própria: Streams. Por enquanto, os laços que você aprendeu são o caminho certo para entender o que acontece por dentro.
Laço ou Arrays?
| Tarefa | Com laço | Com Arrays |
|---|---|---|
| Mostrar | for + print | Arrays.toString(a) |
| Preencher com um valor | for (…) a[i] = v; | Arrays.fill(a, v) |
| Copiar | novo array + for | Arrays.copyOf(a, n) |
| Comparar | for comparando um a um | Arrays.equals(a, b) |
| Ordenar | difícil (algoritmos de ordenação) | Arrays.sort(a) |
| Buscar | busca linear (qualquer array) | Arrays.binarySearch(a, x) (só ordenado) |
| Somar, maior, média | acumulador | Arrays.stream(a).sum() … |
No dia a dia, prefira as ferramentas prontas: são testadas e rápidas. Escrever os laços continua importante para aprender e para os casos que as ferramentas não cobrem.
Quando dá errado
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int[] ordenadas = Arrays.sort(notas);
}
}
$ java Main.java
Main.java:6: error: incompatible types: void cannot be converted to int[]
int[] ordenadas = Arrays.sort(notas);
^
1 error
error: compilation failed
O que quer dizer: o sort é void ("vazio"): ele não devolve nada, só arruma o array que recebeu. Não há o que guardar em ordenadas.
Como consertar: chame sozinho, Arrays.sort(notas);, e use o próprio notas. Se quiser manter o original, copie antes com copyOf e ordene a cópia.
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
Arrays.sort(notas);
}
}
$ java Main.java
Main.java:4: error: cannot find symbol
Arrays.sort(notas);
^
symbol: variable Arrays
location: class Main
1 error
error: compilation failed
Como consertar: faltou import java.util.Arrays; no topo do arquivo.
binarySearch diz que não achou, mas o valor está lá
O array não estava ordenado. Chame Arrays.sort antes. Se a ordem original importa, faça a busca numa cópia ordenada, ou use a busca linear com laço.
Arrays.equals deu false com duas matrizes iguais
Para int[][], use Arrays.deepEquals. O equals só compara o primeiro nível, e lá estão os "crachás" das linhas, que são diferentes.
Referência
| Método | O que faz | Devolve |
|---|---|---|
Arrays.sort(a) | Ordena o próprio array, do menor para o maior | nada (void) |
Arrays.sort(a, critério) | Ordena com outro critério (String.CASE_INSENSITIVE_ORDER, Collator.getInstance()) | nada |
Arrays.toString(a) | Texto [1, 2, 3] | String |
Arrays.deepToString(m) | Texto de uma matriz | String |
Arrays.fill(a, v) | Põe v em todas as posições | nada |
Arrays.copyOf(a, n) | Array novo com os n primeiros (completa com o padrão) | array novo |
Arrays.copyOfRange(a, de, até) | Array novo com a[de] … a[até - 1] | array novo |
Arrays.equals(a, b) | Mesmo tamanho e mesmos valores? | boolean |
Arrays.deepEquals(m1, m2) | O mesmo, para matrizes | boolean |
Arrays.binarySearch(a, x) | Índice de x num array ordenado; negativo se não achar | int |
Arrays.asList(a) | Vê o array como lista (sem mudar o tamanho) | List |
Arrays.stream(a) | Stream dos valores (.sum(), .max(), .average()…) | stream |
Exercícios
1. Ordenar
Complete para ordenar o array idades:
2. Preencher
Complete para colocar -1 em todas as posições de codigos:
3. Um pedaço
Complete para copiar os elementos dos índices 2, 3 e 4 de v:
4. int[] a = {1, 2}; int[] b = {1, 2}; Qual expressão dá true?
5. O que Arrays.copyOf(new int[] {4, 5}, 4) devolve?
6. Antes de usar Arrays.binarySearch, é preciso…
Missão final: mostre as três maiores notas, em ordem crescente: Top 3: [8, 9, 10]. Use Arrays.sort e depois Arrays.copyOfRange para pegar os três últimos (sem escrever os números dos índices: use o length).
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6, 8};
// ordene e copie aqui
int[] top3 = notas;
System.out.println("Top 3: " + Arrays.toString(top3));
}
}
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6, 8};
Arrays.sort(notas);
int[] top3 = Arrays.copyOfRange(notas, notas.length - 3, notas.length);
System.out.println("Top 3: " + Arrays.toString(top3));
}
}
Resumo
java.util.Arraysé a caixa de ferramentas dos arrays; use comimport java.util.Arrays;eArrays.método(array).sortordena o próprio array (não devolve nada). Textos seguem os códigos dos caracteres: maiúsculas antes, acentuadas no fim;Collator.getInstance()dá a ordem do dicionário.toString/deepToStringmostram;fillpreenche.copyOfecopyOfRangecriam arrays novos (início incluído, fim excluído).- Compare conteúdo com
Arrays.equals(matrizes:deepEquals), nunca com==oua.equals(b). binarySearché rápido, mas só funciona com o array ordenado; negativo = não achou.asListvê o array como lista de tamanho fixo;streamabre a porta para as streams.