CodeGym /Cursos /JAVA 25 SELF /Operações básicas com arrays unidimensionais

Operações básicas com arrays unidimensionais

JAVA 25 SELF
Nível 7 , Lição 2
Disponível

1. Array do tipo String

E, em poucas palavras, vamos falar sobre o array do tipo String.

Como já dissemos, um array pode ser de qualquer tipo. Isso significa que podemos criar um array do tipo String. Veja como seria o código se precisássemos escrever um programa que “lê do teclado 10 linhas e as imprime na tela em ordem inversa”.

String[] array = new String[10];	// Criamos um objeto-array com 10 elementos
for (int i = 0; i < 10; i++)		// Laço de 0 a 9
{
   array[i] = console.nextLine();	// Lemos uma linha do teclado e a salvamos na célula do array
}
for (int i = 9; i >= 0; i--)		// Laço de 9 até 0
{
    System.out.println(array[i]);	// Imprimimos na tela o próximo elemento do array
}

O código praticamente não mudou! Só foi preciso trocar o tipo int por String ao criar o array. No resto, é tudo igual!

Conhecendo o null

Eis um enigma — o que há nas células de cada um desses arrays logo após a criação?

int[] numbers = new int[10];
String[] strings = new String[10];
User[] users = new User[10];

Pensando bem, é bem provável que as posições de numbers contenham 0. Correto.

Então, pela mesma lógica, as posições de strings deveriam estar preenchidas com strings vazias — "". Vamos supor.

E com o que estão preenchidas as posições do array users? Com User vazios?

Aí é que está o truque: nem todo tipo de dado tem um “valor padrão”. Por isso, os criadores do Java inventaram uma constante especial — null. null é uma referência vazia. Quando se cria uma variável de um tipo de objeto, seu valor inicial é null: referência para lugar nenhum, ausência de referência.

String name; 	// name contém null
name = "Alex";  // name contém uma referência ao objeto/string "Alex"
name = null; 	// name contém null

Trabalhando com null

Não se pode chamar métodos em um objeto se a referência para ele é null — o objeto simplesmente não existe! Neste código, o programa terminará com erro:

String name; 	// name contém null
String upperName = name.toUpperCase(); // Vai ocorrer NullPointerException: name == null

Quanto ao nosso “enigma”, a resposta é a seguinte:

int[] numbers = new int[10];		// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
String[] strings = new String[10];  // {null, null, null, null, null, null, null, null, null, null}
User[] users = new User[10];		// {null, null, null, null, null, null, null, null, null, null}

Apenas os tipos primitivos têm “valor padrão”. Todos os demais tipos, por padrão, têm o valor null. O valor inicial de String não é uma string vazia. É assim que é.

2. Array do tipo String na memória

Figura 1. Como um objeto String é disposto na memória:

Array do tipo String na memória

Observe que o texto da string não é armazenado diretamente na variável: para ele é alocado um bloco de memória separado. E na variável do tipo String é armazenado o endereço (referência) para o objeto com o texto.

Figura 2. Como um array de inteiros é disposto na memória:

Array int na memória

Você também já viu esta figura.

Figura 3. Como um array de strings é disposto na memória:

Como um array de String é disposto na memória

À esquerda vemos a variável-array do tipo String[] (guarda o endereço do objeto-array).

No meio — o objeto-array do tipo String.

E à direita — os objetos string, que armazenam alguns textos.

Nas posições do objeto-array do tipo String não ficam as próprias strings (textos), mas sim seus endereços (referências). Exatamente como nas variáveis do tipo String ficam os endereços das strings (do texto).

3. Inicialização rápida de arrays em Java

Arrays são muito úteis, por isso os desenvolvedores do Java tentaram tornar o trabalho com eles o mais conveniente possível. E a primeira coisa que fizeram foi simplificar a inicialização do array, o preenchimento com valores iniciais.

Muitas vezes, além dos dados que o programa lê de algum lugar, ele também precisa de dados internos próprios. Por exemplo, precisamos armazenar em um array os números de dias de todos os meses. Como esse código pode ficar:

int[] months = new int[12];
months[0] = 31; // janeiro
months[1] = 28; // fevereiro
months[2] = 31; // março
months[3] = 30; // abril
months[4] = 31; // maio
months[5] = 30; // junho
months[6] = 31; // julho
months[7] = 31; // agosto
months[8] = 30; // setembro
months[9] = 31; // outubro
months[10] = 30; // novembro
months[11] = 31; // dezembro

Mas há um modo mais curto de escrever — obrigado aos criadores do Java:

// número de dias dos meses do ano
int[] months = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Você pode simplesmente listar, separados por vírgula, todos os valores do array!

Acontece que o compilador pode determinar o tipo do container (objeto-array) com base no tipo da variável-array. E para determinar o comprimento do array — basta contar a quantidade de elementos escritos entre chaves.

Por isso, dá para escrever esse código de forma ainda mais curta:

// número de dias dos meses do ano
int[] months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Não é bonito? 🙂 Esse tipo de escrita se chama “inicialização rápida do array”. E, aliás, funciona não só para o tipo int...

// nomes dos meses do ano
String[] months = { "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" };

4. Laço for-each

Percorrer todos os elementos de um array é uma operação tão comum que foi criado um laço especial para isso — for-each. Ele é escrito assim:

for (int score : scores)
{
    System.out.println("Pontos: " + score);
}
Iterando os elementos de um array com for-each

Aqui o laço percorre os elementos sozinho — sem índice manual. Mas não é possível alterar os elementos diretamente (a variável do laço guarda apenas uma cópia do valor); por outro lado, é muito prático apenas “percorrer” o array.

O compilador transforma o código do laço for-each no código abaixo:

for (int i = 0; i < scores.length; i++)
{
    int score = scores[i];
    System.out.println("Pontos: " + score);
}
Como o for-each funciona “por baixo do capô”

Nada de magia. Agora também fica claro por que você não pode alterar os elementos do array por meio da variável score.

Vamos escrever mais um exemplo: vamos encontrar a soma de todos os pontos.

int sum = 0;
for (int score : scores)
{
    sum += score;
}
System.out.println("Soma de todos os pontos: " + sum);
Cálculo da soma dos valores do array com for-each

Quando usar qual laço?

  • Se precisar de índice ou for necessário alterar elementos — use o laço for.
  • Se for apenas para percorrer os valores — for-each é mais rápido e limpo.

5. Alterando elementos do array

E se precisarmos aumentar cada nota em 1 ponto (por exemplo, por bom comportamento)? Aqui é necessário o for clássico com índice, pois só assim podemos modificar os valores no array.

Exemplo: aumentar cada elemento em 1

for (int i = 0; i < grades.length; i++) {
    grades[i] = grades[i] + 1;
}

Após a execução desse código, o array grades terá novos valores.

Por que não dá para fazer isso com for-each?

for (int grade : grades) {
    grade = grade + 1; // Não funciona!
}

Esse código não altera o array, porque grade é uma cópia do valor do array, e não uma referência ao próprio elemento.

6. Cálculos com base em um array

Arrays são usados com frequência para cálculos: soma, média, máximo, mínimo e assim por diante.

Exemplo: soma de todos os elementos do array

int sum = 0;
for (int i = 0; i < grades.length; i++) {
    sum += grades[i]; // o mesmo que sum = sum + grades[i];
}
System.out.println("Soma das notas: " + sum);

Exemplo: busca do valor máximo

int max = grades[0]; // comece pelo primeiro elemento
for (int i = 1; i < grades.length; i++) {
    if (grades[i] > max) {
        max = grades[i];
    }
}
System.out.println("Nota máxima: " + max);

Exemplo: busca do valor mínimo

int min = grades[0]; // comece pelo primeiro elemento
for (int i = 1; i < grades.length; i++) {
    if (grades[i] < min) {
        min = grades[i];
    }
}
System.out.println("Nota mínima: " + min);

Exemplo: cálculo da média aritmética

int sum = 0;
for (int i = 0; i < grades.length; i++) {
    sum += grades[i];
}
double average = (double) sum / grades.length; // é obrigatório fazer cast para double!
System.out.println("Média das notas: " + average);

Atenção: para obter um número fracionário em vez de inteiro, é preciso converter explicitamente a soma para double antes da divisão.

7. Tarefas práticas

Leitura de um array pelo teclado

Muitas vezes é preciso preencher um array com valores informados pelo usuário. Para isso, usamos a classe Scanner e um laço.

Scanner console = new Scanner(System.in);

int n = 5; // tamanho do array
int[] numbers = new int[n];

System.out.println("Digite " + n + " números:");
for (int i = 0; i < n; i++) {
    numbers[i] = console.nextInt();
}

System.out.println("Você digitou:");
for (int i = 0; i < n; i++) {
    System.out.println(numbers[i]);
}

Impressão do array em ordem inversa

Às vezes é preciso imprimir os elementos do array do fim para o começo (por exemplo, para saber quem entrou por último na sala).

for (int i = grades.length - 1; i >= 0; i--) {
    System.out.println("Nota nº " + (i + 1) + ": " + grades[i]);
}

8. Erros típicos ao trabalhar com arrays unidimensionais

Erro nº 1: acesso fora dos limites do array

O problema mais comum é tentar acessar um elemento inexistente. Em Java, isso leva à exceção ArrayIndexOutOfBoundsException. Lembre-se: o último índice válido é arr.length - 1.

int[] arr = new int[5];
System.out.println(arr[5]); // Erro! Índices de 0 a 4.

Erro nº 2: esquecer de inicializar o array

Declarou a variável, mas não criou o array:

int[] arr;
arr[0] = 5; // Erro! O array não foi criado.

É obrigatório criar o array com new:

arr = new int[10];

Erro nº 3: tentar alterar elementos do array via for-each

No laço for-each, a variável é uma cópia do valor, não uma referência ao elemento:

for (int x : arr) {
    x = 100; // Não altera o array!
}

Para alterar valores, use um for com índice.

Erro nº 4: uso incorreto do comprimento do array

Às vezes se confunde o comprimento do array com o último índice:

for (int i = 0; i <= arr.length; i++) { // Erro! Deve ser i < arr.length
    // ...
}

Esse código levará a acesso fora dos limites.

Erro nº 5: conversão de tipos implícita

Se o array é do tipo int, não é possível atribuir diretamente um valor do tipo double:

int[] arr = new int[3];
arr[0] = 3.14; // Erro! 3.14 é double.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION