No trabalho com arrays, é comum encontrarmos situações em que um array deve ser examinado do início ao fim, elemento a elemento. Por exemplo, para calcularmos a soma dos valores contidos em um array, cada elemento do array deve ser exami- nado. A mesma situação ocorre no cálculo de uma média, na busca de um valor, na cópia de um array e assim por diante. Como essas operações do tipo “início ao fim” são tão comuns, Java define uma segunda forma do laço for que as otimiza.
A segunda forma de for implementa um laço de estilo “for-each”. Um laço for- -each percorre um conjunto de objetos, como um array, de maneira rigorosamente sequencial, do início ao fim. Nos últimos anos, os laços de estilo for-each ganharam popularidade tanto entre projetistas quanto entre programadores de linguagens de computador. Originalmente, Java não oferecia um laço de estilo for-each, mas ele foi adicionado com o lançamento do JDK 5. O estilo for-each de for também é chamado de laço for melhorado. Os dois termos são usados neste livro.
A forma geral do laço for de estilo for-each é mostrada abaixo: for(tipo var-iter: conjunto) bloco de instruções
Aqui, tipo especifica o tipo e var-iter especifica o nome de uma variável de itera-
ção que receberá os elementos de um conjunto, um de cada vez, do início ao fim. O
conjunto que está sendo percorrido é especificado por conjunto. Há vários tipos de conjuntos que podem ser usados com for, mas o único tipo usado neste livro é o array. A cada iteração do laço, o próximo elemento do conjunto é recuperado e armazenado em var-iter. O laço se repete até todos os elementos do conjunto terem sido usados. Logo, na iteração por um array de tamanho N, o laço for melhorado obtém os elemen- tos do array em ordem de índice, de 0 a N – 1.
Já que a variável de iteração recebe valores do conjunto, tipo deve ser o mesmo dos (ou compatível com) elementos armazenados no conjunto. Portanto, na iteração em arrays, tipo deve ser compatível com o tipo de elemento do array.
Pergunte ao especialista
P
Além dos arrays, que outros tipos de conjuntos o laço for de estilo for-each per-corre?
R
Um dos mais importantes usos do laço for de estilo for-each é para percorrer o conteúdode um conjunto definido pelo Collections Framework. O Collections Framework é um conjunto de classes que implementa várias estruturas de dados, como listas, vetores, conjuntos e mapas. A discussão do Collections Framework pode ser encontrada no Capítulo 25.
12. Antes de avançar, você pode fazer um teste. Embora SimpleStack armazene caracteres, sua lógica funcionará com outros tipos de dados. Tente modificar SimpleStack para que armazene outro tipo de dado, como int ou double.
Para entender o porquê da existência de um laço de estilo for-each, considere o tipo de laço for que é projetado para executar substituições. O fragmento a seguir usa um laço for tradicional para calcular a soma dos valores de um array:
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int sum = 0;
for(int i=0; i < 10; i++) sum += nums[i];
Para calcularmos a soma, nums é lido em ordem, do início ao fim, elemento a ele- mento. Portanto, o array inteiro é lido em ordem rigorosamente sequencial, o que é feito com a indexação manual do array nums por i, a variável de controle de laço. Além disso, o valor inicial e final da variável de controle de laço e seu incremento devem ser explicitamente especificados.
O laço for de estilo for-each automatiza o laço anterior. Especificamente, ele elimina a necessidade de estabelecermos um contador de laço, determinarmos o valor inicial e final e indexarmos manualmente o array. Ele percorre o array inteiro auto- maticamente, obtendo um elemento de cada vez, em sequência, do início ao fim. Por exemplo, aqui está o fragmento anterior reescrito com o uso de uma versão for-each de for:
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int sum = 0;
for(int x : nums) sum += x;
A cada passagem do laço, x recebe automaticamente um valor igual ao próximo ele- mento de nums. Portanto, na primeira iteração, x contém 1, na segunda, contém 2, e assim por diante. Além da otimização da sintaxe, também evitamos erros relaciona- dos aos limites.
Veja um programa inteiro que demonstra a versão de estilo for-each de for que acabamos de descrever:
// Usa um laço for de estilo for-each. class ForEach {
public static void main(String[] args) {
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int sum = 0;
// Usa o laço for de estilo for-each para exibir e somar os valores. for(int x : nums) { System.out.println("Value is: " + x); sum += x; } System.out.println("Summation: " + sum); } }
A saída do programa é mostrada aqui: Value is: 1 Value is: 2 Value is: 3 Value is: 4 Value is: 5 Value is: 6 Value is: 7 Value is: 8 Value is: 9 Value is: 10 Summation: 55
Como essa saída mostra, o laço for de estilo for-each percorre automaticamente um array em ordem, do índice menor ao maior.
Embora esse tipo de laço for itere até que todos os elementos de um array tenham sido examinados, é possível encerrar o laço antecipadamente usando uma instrução break. Por exemplo, o laço seguinte soma apenas os cinco primeiros elementos de nums:
// Soma apenas os 5 primeiros elementos. for(int x : nums) {
System.out.println("Value is: " + x); sum += x;
if(x == 5) break; // interrompe o laço quando 5 é obtido }
Há um ponto importante que precisa ser conhecido em relação ao laço for de estilo for-each. No que diz respeito ao array subjacente, sua variável de iteração é “somente de leitura”. Uma atribuição à variável de iteração não tem efeito sobre o array subja- cente. Em outras palavras, você não pode alterar o conteúdo do array atribuindo um novo valor à variável de iteração. Por exemplo, considere este programa:
// O laço for-each é somente de leitura. class NoChange {
public static void main(String[] args) {
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for(int x : nums) {
System.out.print(x + " ");
x = x * 10; // sem efeito sobre nums } System.out.println(); for(int x : nums) System.out.print(x + " "); System.out.println(); } }
O primeiro laço for aumenta o valor da variável de iteração por um fator de 10. No entanto, essa atribuição não tem efeito sobre o array subjacente nums, como a saída do segundo laço for ilustra.
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
Como você pode ver, o array nums permanece inalterado.