Java Arrays Multidimensionais
Um array comum é uma fileira de valores. Mas muita coisa no mundo é uma tabela: as notas de cada aluno em cada prova, os assentos de um cinema, o tabuleiro do jogo da velha, uma planilha. Para isso o Java tem os arrays de duas dimensões, chamados de matrizes: arrays cujos elementos são outros arrays.
- O que é uma matriz e como o Java a monta ("um array de arrays").
- Criar com chaves e com
new int[3][4]. - Acessar e mudar um elemento com
[linha][coluna]. - Descobrir o número de linhas e de colunas com
length. - Percorrer com dois laços, somar por linha e por coluna.
- Mostrar a matriz inteira com
Arrays.deepToString. - Arrays irregulares, em que cada linha tem um tamanho.
Os exemplos rodam no terminal da Ana (máquina fictícia notebook, pasta ~/java, JDK 25) com java Main.java. Antes desta aula, veja Arrays e Laços Aninhados: uma matriz é exatamente um array percorrido por dois laços.
A ideia antes do código
A professora Ana anota as notas num caderno quadriculado: uma linha para cada aluno e uma coluna para cada prova.
| Prova 0 | Prova 1 | Prova 2 | Prova 3 | |
|---|---|---|---|---|
| Aluno 0 (Ana) | 7 | 8 | 6 | 9 |
| Aluno 1 (Bruno) | 10 | 9 | 9 | 8 |
| Aluno 2 (Carla) | 5 | 6 | 7 | 6 |
Para achar uma nota, você precisa de dois números: a linha e a coluna. "Aluno 1, prova 2" é a nota 9 em destaque. É como a batalha naval ("B-5") ou as coordenadas de uma planilha ("C3").
Como o Java guarda isso? Com o que você já conhece: cada linha é um array comum de int ({7, 8, 6, 9}), e a tabela é um array dessas linhas. Um array de arrays.
Criar com os valores
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
System.out.println("Aluno 0, prova 0: " + notas[0][0]);
System.out.println("Aluno 1, prova 2: " + notas[1][2]);
System.out.println("Aluno 2, prova 3: " + notas[2][3]);
System.out.println("Linhas (alunos): " + notas.length);
System.out.println("Colunas (provas): " + notas[0].length);
}
}
$ java Main.java Aluno 0, prova 0: 7 Aluno 1, prova 2: 9 Aluno 2, prova 3: 6 Linhas (alunos): 3 Colunas (provas): 4
- int[][]
- O tipo: dois pares de colchetes = duas dimensões. Leia como "array de arrays de
int". - notas =
- O nome e a atribuição.
- {
- Abre o array de fora (o das linhas).
- {7, 8, 6, 9},
- A linha 0: um array comum. As linhas são separadas por vírgula.
- …
- As linhas 1 e 2.
- };
- Fecha o array de fora. Escrever uma linha por linha do código deixa a tabela "desenhada", fácil de conferir.
Acessar: [linha][coluna]
- notas
- A matriz inteira.
- [1]
- Primeiro colchete: a linha 1 (o Bruno). O resultado já é um array:
{10, 9, 9, 8}. - [2]
- Segundo colchete: a coluna 2 dessa linha. O resultado é o
int9.
Os dois índices começam no 0, como em todo array. A ordem é sempre linha primeiro, coluna depois.
Quantas linhas e quantas colunas?
notas.lengthé o tamanho do array de fora: o número de linhas (3).notas[0].lengthé o tamanho da linha 0: o número de colunas (4). Numa matriz "retangular", todas as linhas têm o mesmo tamanho, então qualquer linha serve.
Uma linha sozinha é um array comum, e dá para guardá-la numa variável int[]:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
int[] doBruno = notas[1];
System.out.println(Arrays.toString(doBruno));
System.out.println(notas[1].length);
}
}
$ java Main.java [10, 9, 9, 8] 4
Criar vazia, com tamanho: new int[3][4]
A sala de cinema tem 3 fileiras de 4 cadeiras. No início, todas estão livres (0). Quando alguém compra, a cadeira vira 1:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[][] assentos = new int[3][4];
assentos[0][1] = 1;
assentos[2][3] = 1;
System.out.println(Arrays.deepToString(assentos));
}
}
$ java Main.java [[0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
- new int
- Cria um array novo de
int. - [3]
- 3 linhas.
- [4]
- 4 colunas em cada linha. Total: 12 elementos, todos com o valor padrão (0, ou
0.0,false,null, conforme o tipo; veja Arrays).
Mostrar a matriz: Arrays.deepToString
Você já sabe que println de um array mostra o "crachá" ([I@…) e que Arrays.toString mostra o conteúdo. Com matrizes há uma pegadinha:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
System.out.println(notas);
System.out.println(Arrays.toString(notas));
System.out.println(Arrays.deepToString(notas));
}
}
$ java Main.java [[I@2bbaf4f0 « o crachá da matriz: [[ = duas dimensões [[I@11c20519, [I@70beb599, [I@4e41089d] « toString: os crachás das 3 linhas [[7, 8, 6, 9], [10, 9, 9, 8], [5, 6, 7, 6]] « deepToString: tudo
O Arrays.toString só desce um nível: mostra os elementos do array de fora, e esses elementos são arrays, que aparecem como crachás. O Arrays.deepToString ("deep" = profundo) desce em todos os níveis. Regra: matriz → deepToString.
Percorrer com dois laços
Para passar por todos os elementos, use a receita de Laços Aninhados: o laço de fora anda pelas linhas, o de dentro pelas colunas daquela linha:
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
for (int aluno = 0; aluno < notas.length; aluno++) {
for (int prova = 0; prova < notas[aluno].length; prova++) {
System.out.print(notas[aluno][prova] + "\t");
}
System.out.println();
}
}
}
$ java Main.java 7 8 6 9 10 9 9 8 5 6 7 6
| Parte | O que faz |
|---|---|
aluno < notas.length | Laço de fora: uma volta por linha (3). |
prova < notas[aluno].length | Laço de dentro: uma volta por coluna desta linha. Usar notas[aluno].length (e não um 4 fixo) faz o código funcionar com qualquer tamanho, até com linhas de tamanhos diferentes. |
notas[aluno][prova] | O elemento da vez. |
"\t" e println() | Tabulação entre as colunas; quebra de linha no fim de cada aluno. |
Com for-each
Quando os índices não importam, dois for-each dão conta. Repare no tipo do laço de fora: cada "item" da matriz é uma linha, um int[]:
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
int total = 0;
for (int[] linha : notas) {
for (int nota : linha) {
total += nota;
}
}
System.out.println("Soma de todas as notas: " + total);
}
}
$ java Main.java Soma de todas as notas: 90
Missão: no mapa do cinema, 1 é cadeira vendida e 0 é livre. Percorra a matriz com dois laços, conte as cadeiras vendidas e mostre Total de ingressos vendidos: 5.
public class Main {
public static void main(String[] args) {
int[][] assentos = {
{0, 1, 1, 0},
{1, 0, 0, 0},
{0, 1, 0, 1}
};
int vendidos = 0;
// percorra a matriz aqui
System.out.println("Total de ingressos vendidos: " + vendidos);
}
}
public class Main {
public static void main(String[] args) {
int[][] assentos = {
{0, 1, 1, 0},
{1, 0, 0, 0},
{0, 1, 0, 1}
};
int vendidos = 0;
for (int[] fileira : assentos) {
for (int cadeira : fileira) {
if (cadeira == 1) {
vendidos++;
}
}
}
System.out.println("Total de ingressos vendidos: " + vendidos);
}
}
Somar por linha e por coluna
A média de cada aluno (por linha)
O acumulador nasce dentro do laço de fora, para recomeçar do zero a cada aluno:
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla"};
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
for (int aluno = 0; aluno < notas.length; aluno++) {
int soma = 0;
for (int prova = 0; prova < notas[aluno].length; prova++) {
soma += notas[aluno][prova];
}
double media = (double) soma / notas[aluno].length;
System.out.println(alunos[aluno] + ": média " + media);
}
}
}
$ java Main.java Ana: média 7.5 Bruno: média 9.0 Carla: média 6.0
Se o int soma = 0; ficasse antes dos dois laços, o Bruno herdaria a soma da Ana. O lugar da variável decide o que ela acumula.
A média de cada prova (por coluna)
Para somar uma coluna, os papéis dos laços se invertem: o de fora anda pelas colunas e o de dentro pelas linhas. O acesso continua sendo notas[aluno][prova], linha primeiro:
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
for (int prova = 0; prova < notas[0].length; prova++) {
int soma = 0;
for (int aluno = 0; aluno < notas.length; aluno++) {
soma += notas[aluno][prova];
}
System.out.println("Prova " + (prova + 1) + ": média da turma " + (double) soma / notas.length);
}
}
}
$ java Main.java Prova 1: média da turma 7.333333333333333 Prova 2: média da turma 7.666666666666667 Prova 3: média da turma 7.333333333333333 Prova 4: média da turma 7.666666666666667
As muitas casas decimais são o jeito do println mostrar um double; para arredondar na tela, use printf("%.2f", …), que você verá em Formatar Texto.
Outro tipo: o jogo da velha
Matrizes podem ser de qualquer tipo. Um tabuleiro de jogo da velha é um char[][] 3 × 3:
public class Main {
public static void main(String[] args) {
char[][] velha = {
{'X', 'O', 'X'},
{' ', 'X', 'O'},
{'O', ' ', 'X'}
};
for (char[] linha : velha) {
System.out.println(" " + linha[0] + " | " + linha[1] + " | " + linha[2]);
}
if (velha[0][0] == 'X' && velha[1][1] == 'X' && velha[2][2] == 'X') {
System.out.println("X venceu na diagonal!");
}
}
}
$ java Main.java X | O | X | X | O O | | X X venceu na diagonal!
A diagonal principal são as posições em que a linha é igual à coluna: [0][0], [1][1], [2][2].
Arrays irregulares
Como cada linha é um array separado, nada obriga as linhas a terem o mesmo tamanho. Um array assim se chama irregular (em inglês, jagged, "dentado"). A Ana registra os minutos de corrida de cada semana, e cada semana teve um número diferente de treinos:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[][] treino = new int[3][];
treino[0] = new int[] {30, 45};
treino[1] = new int[] {20, 25, 30, 40};
treino[2] = new int[] {60};
System.out.println(Arrays.deepToString(treino));
for (int semana = 0; semana < treino.length; semana++) {
System.out.println("Semana " + (semana + 1) + ": " + treino[semana].length + " treinos");
}
}
}
$ java Main.java [[30, 45], [20, 25, 30, 40], [60]] Semana 1: 2 treinos Semana 2: 4 treinos Semana 3: 1 treinos
- new int[3][]
- Cria só o array de fora, com 3 linhas, e deixa as colunas em branco. Cada linha começa como
null(ainda não existe). - treino[0] = new int[] {30, 45};
- Cria a linha 0, com 2 elementos.
- treino[1] = …
- Cada linha recebe o seu próprio array, do tamanho que precisar.
Também dá para escrever com chaves: int[][] treino = {{30, 45}, {20, 25, 30, 40}, {60}};. Num array irregular, use sempre treino[linha].length no laço de dentro; um número fixo de colunas não funciona.
As linhas também podem ser criadas num laço. Aqui a linha i tem i + 1 elementos, formando um triângulo:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[][] triangulo = new int[4][];
for (int i = 0; i < triangulo.length; i++) {
triangulo[i] = new int[i + 1];
for (int j = 0; j <= i; j++) {
triangulo[i][j] = j + 1;
}
}
System.out.println(Arrays.deepToString(triangulo));
}
}
$ java Main.java [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
Existe: int[][][] cubo = new int[2][3][4]; e o acesso é cubo[a][b][c]. Pense num prédio (andar, fileira, vaga) ou em várias planilhas (turma, aluno, prova). Na prática, passar de duas dimensões é raro; quando os dados ficam complexos assim, objetos e coleções (Nível 2 e 3) costumam ser mais claros.
Formas de criar: qual usar
| Forma | Exemplo | Quando usar |
|---|---|---|
| Chaves | int[][] m = {{1, 2}, {3, 4}}; | Você já sabe os valores. |
new com as duas medidas | int[][] m = new int[3][4]; | Tabela retangular a preencher depois. |
new só com as linhas | int[][] m = new int[3][]; + m[i] = new int[n]; | Linhas de tamanhos diferentes (irregular). |
Quando dá errado
ArrayIndexOutOfBoundsException na segunda dimensão
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
System.out.println(notas[1][4]);
}
}
$ java Main.java Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4 at Main.main(Main.java:8)
O que quer dizer: a linha 1 existe, mas ela tem 4 colunas (0 a 3), e o código pediu a coluna 4. O length 4 da mensagem é o tamanho da linha, não da matriz. Confira se não trocou linha e coluna: notas[4][1] daria o mesmo erro com length 3.
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
for (int i = 0; i < notas.length; i++) {
for (int j = 0; j < notas.length; j++) {
System.out.print(notas[i][j] + " ");
}
System.out.println();
}
}
}
$ java Main.java 7 8 6 10 9 9 5 6 7 « a quarta prova não apareceu, e nenhum erro foi mostrado
O que aconteceu: o laço de dentro usou notas.length (3 linhas) como limite das colunas (que são 4). Como 3 é menor que 4, nada estourou: a última coluna foi simplesmente ignorada. Se fosse ao contrário (mais linhas que colunas), daria ArrayIndexOutOfBoundsException.
Como consertar: no laço de dentro, use notas[i].length.
NullPointerException num array irregular
public class Main {
public static void main(String[] args) {
int[][] treino = new int[3][];
treino[0][0] = 30;
}
}
$ java Main.java Exception in thread "main" java.lang.NullPointerException: Cannot store to int array because "<local1>[0]" is null at Main.main(Main.java:4)
O que quer dizer: "não dá para guardar no array de int porque treino[0] é null" (o <local1> é a variável treino, sem o nome; veja a explicação em Arrays). Com new int[3][], as linhas ainda não existem.
Como consertar: crie a linha antes de usar: treino[0] = new int[2];. Ou, se todas as linhas têm o mesmo tamanho, new int[3][2].
public class Main {
public static void main(String[] args) {
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
int x = notas[1];
}
}
$ java Main.java
Main.java:8: error: incompatible types: int[] cannot be converted to int
int x = notas[1];
^
1 error
error: compilation failed
O que quer dizer: notas[1] é uma linha inteira (int[]), não um número. Para um elemento, são dois índices: notas[1][2]. Para a linha, a variável precisa ser int[].
Referência
| Código | O que faz |
|---|---|
int[][] m = {{1, 2, 3}, {4, 5, 6}}; | Matriz 2 × 3 com valores |
int[][] m = new int[2][3]; | Matriz 2 × 3 com zeros |
int[][] m = new int[2][]; | 2 linhas ainda não criadas (irregular) |
m[1][2] | Elemento da linha 1, coluna 2 |
m[1] | A linha 1 inteira (um int[]) |
m.length | Número de linhas |
m[i].length | Número de colunas da linha i |
Arrays.deepToString(m) | [[1, 2, 3], [4, 5, 6]] |
for (int[] linha : m) for (int x : linha) | Passa por todos os elementos |
Exercícios
1. Acessar
Em int[][] m = {{1, 2, 3}, {4, 5, 6}};, complete para pegar o número 6:
2. Criar
Complete para criar uma matriz de double com 12 linhas (meses) e 31 colunas (dias):
3. Mostrar
Complete para mostrar o conteúdo inteiro da matriz m:
4. Em int[][] m = new int[4][7];, quanto vale m[0].length?
5. O que Arrays.toString(m) mostra, se m é um int[][]?
6. Para somar uma coluna da matriz, o laço de fora anda por…
Missão final: mostre a soma das notas de cada aluno, uma linha por aluno: Ana: 30, Bruno: 36 e Carla: 24. Lembre de recomeçar a soma a cada aluno.
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla"};
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
// dois laços aqui
}
}
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla"};
int[][] notas = {
{7, 8, 6, 9},
{10, 9, 9, 8},
{5, 6, 7, 6}
};
for (int i = 0; i < notas.length; i++) {
int soma = 0;
for (int j = 0; j < notas[i].length; j++) {
soma += notas[i][j];
}
System.out.println(alunos[i] + ": " + soma);
}
}
}
Resumo
- Uma matriz (
int[][]) é um array de arrays: cada linha é um array comum. - Crie com chaves (
{{…}, {…}}) ou comnew int[linhas][colunas]. - Acesse com
m[linha][coluna], os dois a partir de 0. m.length= linhas;m[i].length= colunas da linhai.- Percorra com dois laços; no de dentro, use
m[i].length. - Para mostrar,
Arrays.deepToString(m)(otoStringsó mostra os crachás das linhas). - Em arrays irregulares (
new int[3][]), cada linha precisa ser criada antes de usar, senão vemNullPointerException.