Java Arrays
A professora Ana tem uma turma com 30 alunos. Para guardar as notas com o que você aprendeu até agora, ela precisaria de 30 variáveis: nota1, nota2, …, nota30. E para tirar a média, uma conta com 30 parcelas. O array resolve isso: uma variável que guarda vários valores do mesmo tipo, cada um numa posição numerada.
- O que é um array e quando usar.
- As duas formas de criar:
new int[5](vazio, com tamanho) e{7, 8, 6}(já com os valores). - Por que as posições (os índices) começam no 0, e como usar o
length. - Os valores que um array novo já tem (os valores padrão).
- Como ler e mudar um elemento.
- O erro mais famoso dos arrays:
ArrayIndexOutOfBoundsException. - Por que
System.out.println(notas)mostra[I@1e9e725a, e como mostrar o array de verdade. - Arrays de
String.
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
Pense num armário de escola com gavetas numeradas, todas do mesmo tamanho, uma ao lado da outra. O armário inteiro tem um nome ("o armário da turma B") e cada gaveta tem um número. Para pegar algo, você diz: "o armário da turma B, gaveta 3".
Um array é esse armário:
- O nome do array é o nome do armário:
notas. - Cada gaveta é um elemento e guarda um valor.
- O número da gaveta é o índice. E aqui vem a surpresa: a primeira gaveta é a de número 0.
- Todas as gavetas guardam o mesmo tipo de coisa: um array de
intsó guardaint. - O número de gavetas é decidido na construção e não muda depois.
| Índice | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| Valor | 7 | 8 | 6 | 9 | 10 |
| Como acessar | notas[0] | notas[1] | notas[2] | notas[3] | notas[4] |
Array, em inglês, quer dizer "arranjo, fileira organizada". Em português também se fala vetor (comum na faculdade) ou arranjo. É tudo a mesma coisa.
Criar um array já com os valores
Quando você já sabe o que vai guardar, escreva os valores entre chaves:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
System.out.println("Primeira nota: " + notas[0]);
System.out.println("Terceira nota: " + notas[2]);
System.out.println("Última nota: " + notas[4]);
System.out.println("Quantidade de notas: " + notas.length);
}
}
$ java Main.java Primeira nota: 7 Terceira nota: 6 Última nota: 10 Quantidade de notas: 5
- int[]
- O tipo: "array de
int". Os colchetes[]são o que transformaint(um número) emint[](vários números). - notas
- O nome da variável. Use plural: ela guarda várias notas.
- =
- Atribuição, como em qualquer variável.
- {7, 8, 6, 9, 10};
- Os valores, entre chaves e separados por vírgula. O Java conta quantos são (5) e cria o array desse tamanho.
E para usar:
- notas
- O array.
- [2]
- O índice entre colchetes: "a gaveta 2". Como a contagem começa no 0, é o terceiro elemento.
Por que começa no 0?
Pense no índice como "quantas gavetas eu ando a partir do começo". A primeira gaveta está a 0 passos do início; a segunda, a 1 passo; a terceira, a 2. Essa é a herança da linguagem C, e quase todas as linguagens populares (Java, C#, JavaScript, Python) seguem a mesma regra. A consequência prática:
- O primeiro elemento é sempre
[0]. - Num array de tamanho 5, o último é
[4]. Em geral, o último é[length - 1]. - O elemento "número N" (contando como gente) está no índice
N - 1.
length: o tamanho
notas.length ("comprimento") diz quantos elementos o array tem. Repare: é sem parênteses. Na String é texto.length(), com parênteses, porque lá é um método; no array, length é um campo fixo. Trocar um pelo outro é um erro muito comum (veja "Quando dá errado").
Um exemplo com os dias da semana, usando o length para achar o último:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] semana = {"domingo", "segunda", "terça", "quarta", "quinta", "sexta", "sábado"};
System.out.println("Hoje é " + semana[5]);
System.out.println("A semana tem " + semana.length + " dias");
semana[0] = "DOMINGO";
System.out.println(Arrays.toString(semana));
System.out.println("Último dia: " + semana[semana.length - 1]);
}
}
$ java Main.java Hoje é sexta « semana[5]: o sexto elemento A semana tem 7 dias [DOMINGO, segunda, terça, quarta, quinta, sexta, sábado] Último dia: sábado « semana[7 - 1] = semana[6]
(O Arrays.toString mostra o array inteiro; ele é explicado mais abaixo, em Imprimir um array.)
Criar um array vazio, com tamanho: new
Às vezes você sabe quantos valores vai guardar, mas ainda não sabe quais: as notas de 5 alunos que ainda vão fazer a prova. Aí você cria o array com new e o tamanho:
public class Main {
public static void main(String[] args) {
int[] notas = new int[5];
System.out.println("Antes: " + notas[0] + " " + notas[1] + " " + notas[2]);
notas[0] = 7;
notas[1] = 8;
notas[2] = 6;
System.out.println("Depois: " + notas[0] + " " + notas[1] + " " + notas[2]);
System.out.println("Tamanho: " + notas.length);
}
}
$ java Main.java Antes: 0 0 0 « um array novo de int já vem cheio de zeros Depois: 7 8 6 Tamanho: 5 « o tamanho é 5, mesmo com só 3 notas preenchidas
- int[] notas
- Declara a variável do tipo "array de
int". - =
- Atribuição.
- new
- "Novo": pede ao Java para construir um array novo na memória. A mesma palavra cria objetos, como você verá em Classes e Objetos.
- int[5];
- O tipo dos elementos e, entre colchetes, o tamanho: 5 gavetas, de
[0]a[4].
O tamanho pode vir de uma variável ou de uma conta (new int[quantidadeDeAlunos]), mas, uma vez criado, o array não cresce nem diminui. Para listas que mudam de tamanho, o Java tem o ArrayList.
Os valores padrão
Um array criado com new nunca vem com "lixo": cada tipo tem um valor inicial, chamado valor padrão:
public class Main {
public static void main(String[] args) {
int[] inteiros = new int[2];
double[] decimais = new double[2];
boolean[] marcados = new boolean[2];
char[] letras = new char[2];
String[] nomes = new String[2];
System.out.println("int: " + inteiros[0]);
System.out.println("double: " + decimais[0]);
System.out.println("boolean: " + marcados[0]);
System.out.println("char: código " + (int) letras[0]);
System.out.println("String: " + nomes[0]);
}
}
$ java Main.java int: 0 double: 0.0 boolean: false char: código 0 « o caractere de código 0, que não aparece na tela String: null « null = "nenhum texto ainda"
| Tipo do array | Valor padrão |
|---|---|
int[], long[], short[], byte[] | 0 |
double[], float[] | 0.0 |
boolean[] | false |
char[] | o caractere de código 0 ('\u0000'), invisível |
String[] e qualquer outro objeto | null ("nada") |
Isso é diferente das variáveis comuns dentro do main, que não têm valor padrão: usar uma sem dar valor é erro de compilação (variable … might not have been initialized, veja Variáveis).
Chaves ou new?
| Forma | Exemplo | Quando usar |
|---|---|---|
| Chaves (inicializador) | int[] notas = {7, 8, 6}; | Você já sabe os valores. Só vale na mesma linha da declaração. |
new com tamanho | int[] notas = new int[30]; | Você sabe quantos, mas os valores virão depois (do teclado, de uma conta, de um arquivo). |
new com chaves | notas = new int[] {7, 8, 6}; | Você quer dar valores a uma variável já declarada, ou passar um array direto para um método. |
| Colchetes no nome (estilo C) | int notas[] = {7, 8, 6}; | Funciona, mas evite: o estilo Java é int[] notas, com o tipo inteiro junto. |
Mudar um elemento
Cada elemento funciona como uma variável comum: dá para atribuir, somar, usar ++ e --. A professora revisou duas provas: a terceira nota sobe 2 pontos e a última perde 1:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
notas[2] = notas[2] + 2;
notas[4]--;
System.out.println(Arrays.toString(notas));
}
}
$ java Main.java [7, 8, 8, 9, 9]
Missão: a nota do terceiro aluno foi lançada errada: era 10. Acrescente uma linha que corrige esse elemento, para a saída ficar [7, 8, 10, 9, 10]. Lembre: terceiro aluno, índice…?
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
// corrija a nota aqui
System.out.println(Arrays.toString(notas));
}
}
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
notas[2] = 10;
System.out.println(Arrays.toString(notas));
}
}
Cuidado: = não copia o array
A variável do array guarda o endereço do armário, não as gavetas. Por isso, int[] outro = original; não cria um segundo armário: cria um segundo nome para o mesmo armário.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] original = {7, 8, 6};
int[] outro = original;
outro[0] = 0;
System.out.println("original: " + Arrays.toString(original));
System.out.println("outro: " + Arrays.toString(outro));
}
}
$ java Main.java original: [0, 8, 6] « mudou também! outro: [0, 8, 6]
Mexer em outro[0] mudou o original, porque os dois nomes apontam para o mesmo array. Para ter uma cópia de verdade, use Arrays.copyOf, ensinado em A Classe Arrays.
Fora dos limites: ArrayIndexOutOfBoundsException
O que acontece se você pede uma gaveta que não existe? O array notas tem 5 elementos (índices 0 a 4). Vamos pedir o índice 5:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
System.out.println(notas[5]);
}
}
$ java Main.java Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 at Main.main(Main.java:4)
Repare que o programa compila: o javac não verifica índices, porque normalmente eles vêm de contas e variáveis que só têm valor quando o programa roda. O erro aparece durante a execução, como uma exceção (o assunto de O que são Exceções). Vamos ler a mensagem por partes:
- Exception in thread "main"
- "Exceção na linha de execução main": o programa parou por um erro.
- java.lang.ArrayIndexOutOfBoundsException:
- O tipo do erro: "índice de array fora dos limites" (out of bounds = "fora da área permitida").
- Index 5 out of bounds for length 5
- O detalhe: "o índice 5 está fora dos limites para o tamanho 5". Num array de tamanho 5, o maior índice válido é 4.
- at Main.main(Main.java:4)
- Onde: no método
mainda classeMain, arquivoMain.java, linha 4.
Índice negativo também não existe:
$ java Main.java « o mesmo programa, agora com notas[-1] Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 5 at Main.main(Main.java:4)
Os casos mais comuns na vida real: usar notas[notas.length] para pegar o último (o certo é length - 1) e laços com <= no lugar de < (for (int i = 0; i <= notas.length; i++) dá uma volta a mais). Os laços sobre arrays têm a sua aula: Percorrer Arrays.
Imprimir um array: o mistério do [I@
A primeira coisa que todo iniciante tenta é mandar o array inteiro para o println. Veja o que sai:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
double[] precos = {4.5, 12.0};
String[] frutas = {"maçã", "uva"};
System.out.println(notas);
System.out.println(precos);
System.out.println(frutas);
System.out.println(Arrays.toString(notas));
System.out.println(Arrays.toString(precos));
System.out.println(Arrays.toString(frutas));
}
}
$ java Main.java [I@1e9e725a [D@15d9bc04 [Ljava.lang.String;@473b46c3 [7, 8, 6, 9, 10] [4.5, 12.0] [maçã, uva]
As três primeiras linhas não são um erro nem lixo: é o "crachá" do array, o jeito padrão que o Java tem de descrever um objeto que não sabe se mostrar. Ele tem três partes:
- [
- "Isto é um array".
- I
- O tipo dos elementos, num código de uma letra:
I=int,D=double,Z=boolean,C=char,J=long. Para objetos,L+ o nome completo da classe +;, comoLjava.lang.String;. - @
- Separador.
- 1e9e725a
- Um número de identificação do objeto (o hash code), escrito em hexadecimal. Não tem nada a ver com os valores guardados e não serve para você.
Para ver o conteúdo, use Arrays.toString(array), que monta o texto [elemento, elemento, …]. Ele mora na classe java.util.Arrays, por isso o import java.util.Arrays; no topo (sem ele, o javac diz cannot find symbol). Essa classe tem várias outras ferramentas, como ordenar e copiar: veja A Classe Arrays. Outra forma é percorrer o array com um laço e mostrar elemento por elemento, como em Percorrer Arrays.
char?
É a exceção: System.out.println tem uma versão especial para char[] e mostra as letras juntas, como um texto. char[] l = {'o', 'i'}; System.out.println(l); mostra oi. Mas basta juntar com texto ("Letras: " + l) para voltar o "crachá" [C@….
Arrays de String
Tudo o que você viu vale para textos. Um array de nomes, de frutas, de dias da semana:
String[] alunos = {"Ana", "Bruno", "Carla"};
String[] chamada = new String[30]; // 30 posições, todas null
A diferença está no valor padrão: null. Ele significa "esta gaveta ainda não tem texto nenhum", e não é o mesmo que um texto vazio "". Mostrar um null funciona (aparece a palavra null), mas usar um método nele derruba o programa:
public class Main {
public static void main(String[] args) {
String[] nomes = new String[3];
nomes[0] = "Ana";
System.out.println(nomes[0].length());
System.out.println(nomes[1].length());
}
}
$ java Main.java 3 « "Ana" tem 3 letras Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local1>[1]" is null at Main.main(Main.java:6)
NullPointerException ("exceção de ponteiro nulo") é a exceção mais comum do Java. A mensagem diz: "não dá para chamar String.length() porque <local1>[1] é null". O <local1> é como o Java chama a variável nomes quando o programa foi compilado sem os nomes das variáveis (o padrão do java Main.java e do javac comum). Compilando com javac -g Main.java, que guarda esses nomes, a mesma linha fica mais clara:
$ javac -g Main.java $ java Main 3 Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "nomes[1]" is null at Main.main(Main.java:6)
A gaveta nomes[1] nunca recebeu um nome. Preencha antes de usar, ou teste com if (nomes[1] != null).
Quando dá errado
public class Main {
public static void main(String[] args) {
int[] notas = new int[];
}
}
$ java Main.java
Main.java:3: error: array dimension missing
int[] notas = new int[];
^
1 error
error: compilation failed
O que quer dizer: "falta a dimensão do array". Com new, o Java precisa saber o tamanho: new int[5]. Ou então os valores: new int[] {7, 8, 6}.
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8.5, 6};
}
}
$ java Main.java
Main.java:3: error: incompatible types: possible lossy conversion from double to int
int[] notas = {7, 8.5, 6};
^
1 error
error: compilation failed
O que quer dizer: "conversão com possível perda de double para int". Todos os elementos têm o mesmo tipo; um int[] não guarda o 8.5. O ^ aponta o intruso.
Como consertar: se as notas podem ter vírgula, use double[] notas = {7, 8.5, 6}; (o 7 e o 6 viram 7.0 e 6.0 sozinhos).
public class Main {
public static void main(String[] args) {
int[] notas;
notas = {7, 8, 6};
}
}
$ java Main.java
Main.java:4: error: illegal start of expression
notas = {7, 8, 6};
^
Main.java:4: error: not a statement
notas = {7, 8, 6};
^
Main.java:4: error: ';' expected
notas = {7, 8, 6};
^
3 errors
error: compilation failed
O que quer dizer: as chaves sozinhas só valem na mesma linha da declaração. Numa atribuição depois, o javac não entende o { e se perde (três erros, uma causa).
Como consertar: notas = new int[] {7, 8, 6};.
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6};
System.out.println(notas.length());
}
}
$ java Main.java
Main.java:4: error: cannot find symbol
System.out.println(notas.length());
^
symbol: method length()
location: variable notas of type int[]
1 error
error: compilation failed
O que quer dizer: "não encontro o método length() na variável notas, do tipo int[]". Array não tem método length(); tem o campo length.
Como consertar: notas.length, sem parênteses. Para lembrar: array, sem parênteses; String, com: nome.length().
import
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8};
System.out.println(Arrays.toString(notas));
}
}
$ java Main.java
Main.java:4: error: cannot find symbol
System.out.println(Arrays.toString(notas));
^
symbol: variable Arrays
location: class Main
1 error
error: compilation failed
O que quer dizer: o javac não conhece o nome Arrays. A classe existe, mas mora no pacote java.util, e é preciso avisar que você vai usá-la (veja Pacotes e import).
Como consertar: acrescente import java.util.Arrays; na primeira linha do arquivo, antes de public class Main.
NegativeArraySizeException
public class Main {
public static void main(String[] args) {
int quantidade = -3;
int[] notas = new int[quantidade];
}
}
$ java Main.java Exception in thread "main" java.lang.NegativeArraySizeException: -3 at Main.main(Main.java:4)
O que quer dizer: "tamanho de array negativo: -3". Não existe armário com -3 gavetas. Acontece quando o tamanho vem de uma conta ou do usuário; valide o número antes (um tamanho 0 é permitido e cria um array vazio).
Referência
| Código | O que faz |
|---|---|
int[] a = {1, 2, 3}; | Cria um array com esses valores (tamanho 3) |
int[] a = new int[5]; | Cria um array de 5 elementos, todos com o valor padrão (0) |
a = new int[] {1, 2, 3}; | Cria e atribui a uma variável já declarada |
a[0] | O primeiro elemento |
a[a.length - 1] | O último elemento |
a[2] = 10; | Muda o terceiro elemento |
a.length | Quantidade de elementos (sem parênteses) |
Arrays.toString(a) | Texto [1, 2, 3] (precisa de import java.util.Arrays;) |
System.out.println(a) | Mostra o "crachá", como [I@1e9e725a, e não o conteúdo |
String[] s = new String[3]; | Três posições com null |
Exercícios
1. Criar com valores
Complete para criar um array com os preços 10, 20 e 30:
2. Criar vazio
Complete para criar um array de 12 double (um por mês):
3. O último
Complete o índice do último elemento, sem escrever o número:
4. Em int[] v = {4, 8, 15, 16, 23};, quanto vale v[3]?
5. O que new boolean[4] contém logo depois de criado?
6. System.out.println(notas) mostrou [I@1e9e725a. O que isso significa?
7. Num array com length igual a 10, quais são os índices válidos?
Missão final: este programa quer mostrar a última nota, mas termina com ArrayIndexOutOfBoundsException. Rode, leia a mensagem e conserte usando o length (sem escrever o número 4).
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
System.out.println("Última nota: " + notas[notas.length]);
}
}
public class Main {
public static void main(String[] args) {
int[] notas = {7, 8, 6, 9, 10};
System.out.println("Última nota: " + notas[notas.length - 1]);
}
}
Resumo
- Um array guarda vários valores do mesmo tipo numa variável só. O tipo se escreve com colchetes:
int[],String[]. - Crie com os valores (
{7, 8, 6}) ou com o tamanho (new int[5]). O tamanho não muda depois. - Os índices vão de 0 a
length - 1.lengthnão tem parênteses. - Arrays novos vêm com valores padrão:
0,0.0,falseounull. - Um índice fora dos limites compila, mas derruba o programa com
ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5. println(array)mostra o "crachá" ([I@…); para ver o conteúdo,Arrays.toString(array).int[] b = a;não copia: os dois nomes apontam para o mesmo array.