41bb726c

Dia 5

Tabelas, condicionais e laços

Laura Lemay


CONTEÚDOS

Embora possa escrever a utilização de programas Java o que aprendeu por enquanto, aqueles programas seriam bastante enfadonhos. A maior parte do bom material em Java ou em qualquer linguagem de programação resulta quando tem tabelas para guardar valores em e construtos de fluxo do controle (laços e condicionais) para realizar bits diferentes de um programa baseado em testes. Hoje, descobrirá sobre o seguinte:

Tabelas

As tabelas em Java, como em outras línguas, são um modo de guardar coleções de itens em uma unidade única. A tabela tem algum número de fendas, cada uma das quais mantém um item individual. Pode acrescentar e eliminar itens àquelas fendas como necessário. Diferentemente de em outras línguas, contudo, as tabelas em Java são objetos reais que podem passar-se em volta e tratar-se como outros objetos.

Novo tempo
Uma tabela é uma coleção de itens. Cada fenda na tabela pode manter um objeto ou um valor primitivo. As tabelas em Java são objetos que podem tratar-se como outros objetos na língua.

As tabelas podem conter qualquer tipo do valor de elemento (tipos primitivos ou objetos), mas não pode guardar tipos diferentes em uma tabela única. Pode ter uma tabela de números inteiros ou uma tabela de cadeias ou uma tabela de tabelas, mas não pode ter uma tabela que contém, por exemplo, tanto cadeias como números inteiros.

Para criar uma tabela em Java, usa três passos:

  1. Declare que uma variável mantenha a tabela.
  2. Crie uma nova tabela objetam e destinam-no à variável de tabela.
  3. Coisas de loja naquela tabela.

Declaração de variáveis de tabela

O primeiro passo na criação de uma tabela cria uma variável que manterá a tabela, tão como ia qualquer outra variável. As variáveis de tabela indicam o tipo do objeto que a tabela manterá (como fazem para qualquer variável) e o nome da tabela, seguida de suportes de forma triangular vazios ([]). O seguinte é todas as declarações de variável de tabela típicas:

String difficultWords[];

Point hits[];

int temps[];

Um método alternativo de definir uma variável de tabela deve pôr os suportes de forma triangular depois do tipo em vez de depois da variável. São equivalentes, mas esta última forma muitas vezes é muito mais legível. Deste modo, por exemplo, estas três declarações podem escrever-se como isto:

String[] difficultWords;

Point[] hits;

int[] temps;

Criação de objetos de tabela

O segundo passo deve criar um objeto de tabela e destiná-lo àquela variável. Há dois modos de fazer isto:

O primeiro caminho é usar o operador new para criar um novo exemplo de uma tabela:

String[] names = new String[10];

Aquela linha cria uma nova tabela de String s com 10 fendas (elementos às vezes chamados). Quando cria um novo objeto de tabela usando new, deve indicar quantas fendas que a tabela manterá. Esta linha não põe objetos de String reais nas fendas-you'll têm de fazer isto depois.

Os objetos de tabela podem conter tipos primitivos como números inteiros ou booleans, como podem conter objetos:

int[] temps = new int[99];

Quando cria um objeto de tabela usando new, todas as suas fendas inicializam-se para você (0 de tabelas numéricas, false do booleano, '\0' de tabelas de caráter e null de objetos). Então pode destinar valores real ou objetos às fendas naquela tabela. Também pode criar uma tabela e inicializar os seus conteúdos ao mesmo tempo. Em vez de usar new para criar o novo objeto de tabela, cerque os elementos da tabela dentro de tiras, separadas por vírgulas:

String[] chiles = { "jalapeno", "anaheim", "serrano",
    "habanero", "thai" };

Nota técnica
Observe que a palavra-chave de Java null se refere a um objeto nulo (e pode usar-se para qualquer referência a objeto). Não é equivalente ao zero ou o caráter de '\0' como o NULL constante está em C.

Cada um dos elementos dentro das tiras deve ser do mesmo tipo e deve ser o mesmo tipo que a variável que considera que a tabela (o compilador de Java se queixará se não são). Uma tabela o tamanho do número de elementos que incluiu vai se criar automaticamente para você. Este exemplo cria uma tabela de objetos de String denominados chiles que contém cinco elementos.

Acesso de elementos de tabela

Uma vez que tem uma tabela com valores iniciais, pode testar e modificar os valores em cada fenda daquela tabela. Para alcançar um valor guardado dentro de uma tabela, use a expressão de subscrito de tabela ([]):

myArray[subscript];

A parte de myArray desta expressão é uma variável mantendo um objeto de tabela, embora também possa ser uma expressão que resulta em uma tabela. A parte de subscript da expressão, dentro dos suportes de forma triangular, especifica o número da fenda dentro da tabela ao acesso. Os subscritos de tabela começam com 0, como fazem em C e C ++. Deste modo, uma tabela com 10 elementos tem 10 fendas de tabela acessadas 0 inferior que usa a 9.

Observe que todos os subscritos de tabela se verificam quando o seu programa Java se dirige para assegurar-se que são dentro dos limites da tabela (maiores do que ou igual a 0 mas menos do que o comprimento da tabela). Diferentemente de em C, é impossível em Java acessar ou destinar um valor a uma fenda de tabela do lado de fora dos limites da tabela (por meio disso evitação de muitos problemas comuns e defeitos que resultam do trasbordo dos limites de uma tabela no parecido às linguagem C). Observe duas seguintes afirmações, por exemplo:

String[] arr = new String[10];
arr[10] = "eggplant";

Um programa com aquela afirmação última nele produz um erro naquela linha quando tenta dirigi-lo. (De fato, para ser mais tecnicamente correto, lança uma exceção. Aprenderá mais sobre exceções no Dia 18, "Multienfiando".) a tabela guardada em arr tem só 10 fendas numeradas de 0, o elemento em 10 inferior não existe.

Se o subscrito de tabela se calcular no tempo de execução (por exemplo, como parte de um laço) e terminar do lado de fora dos limites da tabela, o intérprete de Java também produz um erro.

Como pode conservar-se de atravessar correndo acidentalmente o fim de uma tabela nos seus próprios programas? Pode testar para o comprimento da tabela nos seus programas usando a variável-it's de exemplo de length disponível para todos os objetos de tabela, apesar do tipo:

int len = arr.length // returns 10

Contudo, somente para repetir: O comprimento da tabela é 10, mas o seu subscrito só pode aproximar-se de 9. As tabelas começam a numerar de 0. Sempre que trabalhe com tabelas, se lembre disto e subtraia 1 do comprimento da tabela para adquirir o seu elemento maior.

Modificação de elementos de tabela

Para destinar um valor de elemento a uma determinada fenda de tabela, simplesmente ponha uma afirmação de nomeação depois da expressão de acesso a tabela:

myarray[1] = 15;
sentence[0] = "The";
sentence[10] = sentence[0];

Uma coisa importante a observar consiste em que uma tabela de objetos em Java é uma tabela de referências para aqueles objetos (semelhante de alguns modos a uma tabela de ponteiros em C ou C ++). Quando destina um valor a uma fenda em uma tabela, cria uma referência para aquele objeto, como faz para uma variável clara. Quando move valores em volta de tabelas interiores (como naquela linha última), somente redestina a referência; não copia o valor de uma fenda ao outro. As tabelas de tipos primitivos como int s ou float s realmente copiam os valores de uma fenda ao outro.

As tabelas de referências para objetos, ao contrário dos próprios objetos, são especialmente úteis porque pode ter múltiplas referências para os mesmos objetos dentro e fora de tabelas. Por exemplo, pode destinar um objeto contido em uma tabela a uma variável e referir-se àquele mesmo objeto usando a variável ou a posição de tabela.

Adquiriu-o? As tabelas são bastante simples criar e modificar, mas fornecem um montante enorme da funcionalidade de Java. Vai se encontrar que bate em tabelas muito o mais usa Java.

Para terminar a discussão sobre tabelas, aqui está um programa simples que mostra como criar, inicializar, modifique e examine partes de uma tabela. A listagem 5.1 tem o código.


A listagem 5.1. Várias operações de tabela simples.
 1: class ArrayTest {
 2:
 3:    String[] firstNames = { "Dennis", "Grace", "Bjarne", "James" };
 4:    String[] lastNames = new String[firstNames.length];
 5:
 6:    void printNames() {
 7:      int i = 0;
 8:       System.out.println(firstNames[i]
 9:          + " " + lastNames[i]);
10:      i++;
11:       System.out.println(firstNames[i]
12:         + " " + lastNames[i]);
13:       i++;
14:       System.out.println(firstNames[i]
15:          + " " + lastNames[i]);
16:       i++;
17:      System.out.println(firstNames[i]
18:          + " " + lastNames[i]);
19:    }
20:
21:    public static void main (String args[]) {
22:      ArrayTest a = new ArrayTest();
23:       a.printNames();
24:       System.out.println("----------");
25:       a.lastNames[0] = "Ritchie";
26:       a.lastNames[1] = "Hopper";
27:      a.lastNames[2] = "Stroustrup";
28:       a.lastNames[3] = "Gosling";
29:       a.printNames();
30:   }
31:}

Dennis null
Grace null
Bjarne null
James null
----------
Dennis Ritchie
Grace Hopper
Bjarne Stroustrup
James Gosling

Análise
Este exemplo um tanto verboso mostra-lhe como criar e usar tabelas. A classe que criamos aqui, ArrayTest, tem duas variáveis de exemplo que mantêm tabelas de objetos de String . O firstNames primeiro, chamado, declara-se e inicializa-se na mesma linha (linha 3) para conter quatro cadeias. A segunda variável de exemplo, lastNames, declara-se e cria-se na linha 4, mas nenhum valor inicial se coloca nas fendas. Também observe que criamos a tabela de lastNames para ter exatamente o mesmo número de fendas que a tabela de firstNames usando a variável de firstNames.length como o índice de tabela inicial. A variável de exemplo de length em objetos de tabela devolve o número de fendas na tabela.

A classe de ArrayTest também tem dois métodos: printNames() e main(). printNames(), definido em linhas 6 para 19, é um método de serviço que realmente apenas atravessa o firstNames e tabelas de lastNames em sequência, imprimindo os valores de cada fenda, um nome por linha. Observe que o índice de tabela que definimos aqui (i) se estabelece inicialmente em 0 porque fendas de tabela de Java toda a numeração de partida de 0.

Finalmente, há main(), que executa as ações reais deste exemplo. O método de main() aqui faz quatro coisas:

Observar
Quem são as pessoas neste exemplo? São os inventores das linguagens de programação de computador. Dennis Ritchie é o inventor de C, Bjarne Stroustrup fez C ++, atribuem a Grace Hopper o COBOL, e, finalmente, James Gosling é o desenhista principal de Java.

Uma outra nota que devo fazer sobre a Listagem 5.1 é que é um exemplo terrível de programar o estilo. Normalmente quando trata com tabelas não codifica muito o número de elementos no código como temos aqui; em vez disso usa um laço para atravessar cada elemento da tabela à sua vez. Isto faz o código muito mais curto e, em muitos casos, mais fáceis ler. Aprenderá sobre laços depois nesta seção, e reescreveremos este exemplo para que trabalhe mais flexivelmente.

Tabelas multidimensionais

Uma coisa última a observar sobre tabelas antes que mudemos ao resto desta lição é sobre tabelas multidimensionais. Java não apoia diretamente tabelas multidimensionais. Contudo, pode declarar e criar uma tabela de tabelas (e aquelas tabelas podem conter tabelas, e assim por diante, para contudo muitas dimensões das quais precisa) e acesse as tabelas como ia o C-estilo tabelas multidimensionais:

int coords[][] = new int[12][12];
coords[0][0] = 1;
coords[0][1] = 2;

Afirmações de bloco

Antes que nos lancemos aos dois terços últimos desta lição, vamos tomar uma pequena volta em um tópico não mencionei um lote inteiro até este ponto (mas será importante mais tarde): afirmações de bloco.

Uma afirmação de bloco é simplesmente um grupo de afirmações de Java rodeadas de tiras ({}). Viu bloqueia um lote inteiro já; usou uma afirmação de bloco para conter as variáveis e métodos em uma definição de classe, e dentro daquele bloco também usou blocos para manter o corpo de uma definição de método. A tira inicial abre o bloco, e a tira final fecha o bloco final mais próximo. Fácil, certo?

Também pode usar blocos até além disso, dentro de definições de método. A regra consiste em que pode usar um bloco em qualquer lugar uma afirmação única iria. Cada afirmação dentro do bloco então realiza-se em sequência.

Novo termo
Uma afirmação de bloco é um grupo de afirmações de Java individuais cercadas em tiras ({}). Pode pôr uma afirmação de bloco em qualquer lugar uma afirmação única pode ir.

Assim, qual é a diferença entre utilização de um grupo de afirmações individuais e utilização de um bloco? O bloco cria um novo alcance variável local das afirmações dentro dele. Isto significa que pode declarar e usar variáveis locais dentro de um bloco, e aquelas variáveis deixarão de existir depois que o bloco termina-se realizando. Por exemplo, aqui está um bloco dentro de uma definição de método que declara um novo y variável. Não pode usar y do lado de fora do bloco no qual se declara:

void testblock() {
    int x = 10;
    { // start of block
      int y = 50;
      System.out.println("inside the block:");
      System.out.println("x:" + x);
      System.out.println("y:" + y);
    } // end of block
}

Os blocos não se usam normalmente nisto sozinho pelo caminho em uma definição de método, com declarações variáveis casuais dentro deles. Viu pela maior parte blocos até este ponto classe circundante e definições de método, mas outro uso muito comum de afirmações de bloco está nos construtos de fluxo de controle sobre os quais aprenderá no resto da lição de hoje.

Condicionais de if

A afirmação condicional do if usa-se quando quer realizar bits diferentes do código baseado em um teste simples. as condições de if são quase idênticas a afirmações de if em C: contêm a palavra-chave if, seguido de um teste booleano, seguido de uma afirmação única ou de uma afirmação de bloco para realizar se o teste for true. Aqui está um exemplo simples que imprime a mensagem x is smaller than y só se o valor de x for menos do que o valor de y:

if (x < y)
    System.out.println("x is smaller than y");

Uma palavra-chave de else opcional fornece a afirmação alternativa para realizar se o teste for false:

if (x < y)
    System.out.println("x is smaller than y");
else System.out.println("y is bigger");

Novo termo
O if condicional realiza bits diferentes do código baseado no resultado de um teste booleano único.

Nota técnica
A diferença entre condicionais de if em Java e C ou C ++ é que o teste deve devolver um valor booleano (true ou false). Diferentemente de em C, o teste não pode devolver um número inteiro.

Usando if, só pode incluir uma afirmação única como o código para realizar depois do teste (neste caso, o método de System.out.println() para cada um). Mas porque um bloco pode aparecer em qualquer lugar uma afirmação única pode, se quiser fazer mais do que somente uma coisa (como normalmente vai), pode cercar aquelas afirmações dentro de um bloco:

if (engineState == true )
    System.out.println("Engine is already on.");
else {
    System.out.println("Now starting Engine.");
    if (gasLevel >= 1)
        engineState = true;
    else System.out.println("Low on gas! Can't start engine.");
}

Este exemplo usa o teste (engineState == true). Para testes booleanos deste tipo, um atalho comum simplesmente deve incluir a primeira parte da expressão em vez de explicitamente testar o seu valor contra true ou false. Como é uma variável booleana, automaticamente devolve true ou false absolutamente sozinho, portanto não tem de testá-lo explicitamente para aquele valor. Aqui está uma versão mais curta do código prévio, com o teste substituído com a versão de estenografia:

if (engineState)
    System.out.println("Engine is on.");
else System.out.println("Engine is off.");

A listagem 5.2 mostra outro exemplo simples - este na forma aplicada cheia. A classe de Peeper contém um método de serviço chamado peepMe(), que testa um valor para ver se é plano. Se for, imprime Peep! para a tela.


A listagem 5.2. A classe de Peeper.
 1: class Peeper {
 2:
 3:    void peepMe(int val) {
 4:       System.out.println("Value is "
 5:          + val + ". ");
 6:       if (val % 2 == 0)
 7:         System.out.println("Peep!");
 8:    }
 9:
10:   public static void main (String args[]) {
11:      Peeper p = new Peeper();
12:
13:       p.peepMe(1);
14:       p.peepMe(2);
15:        p.peepMe(54);
16:       p.peepMe(77);
17:      p.peepMe(1346);
18:    }
19: }

Value is 1.
Value is 2.
Peep!
Value is 54.
Peep!
Value is 77.
Value is 1346.
Peep!

Análise
O coração da classe de Peeper é o método de peepMe() (linhas 3 para 8), onde os valores se testam e uma mensagem apropriada imprime-se. Diferentemente dos métodos definiu em exemplos prévios, observe que a definição de peepMe() inclui um argumento de número inteiro único (ver a linha 3). O método de peepMe() começa imprimindo o valor que se passou para ele. Então aquele argumento testa-se, usando um if condicional, para ver se é um número par. (O teste de módulo, como se lembrará do Dia 3, "Fundamentos de Java", devolve o resto da divisão do seu operands. Assim, se o resto de um número dividido por 2 é 0, é um número par.) Se o número for até, Peep! imprime-se (aprenderá mais sobre a definição de métodos com argumentos amanhã).

Usaremos o método a main(), como sempre, nesta aplicação para criar um novo exemplo de Peeper e testá-lo, chamando o método de peepMe() repetidamente com valores diferentes. Na produção, só os valores que são até adquirem uma mensagem de Peep!.

O operador condicional

Uma alternativa para a utilização do if e palavras-chave de else em uma afirmação condicional deve usar o operador condicional, às vezes chamado o operador ternário (ternário significa três; o operador condicional tem três partes).

O operador condicional é uma expressão, subentendendo que devolve um valor (diferentemente do if mais geral, que só pode resultar em uma afirmação ou bloco que se realiza). O operador condicional é o mais útil para condicionais muito curtos ou simples e parece a isto:

test ? trueresult : falseresult;

test é uma expressão booleana que devolve true ou false, como o teste na afirmação de if. Se o teste for true, o operador condicional devolve o valor de trueresult; se for false, devolve o valor de falseresult. Por exemplo, os seguintes testes condicionais os valores de x e y, devolve os mais pequenos dos dois e destina aquele valor ao smaller variável:

int smaller = x < y ? x : y;

O operador condicional tem uma precedência muito baixa; isto é, só avaliava normalmente depois que todas as suas subexpressões avaliam-se. Os únicos operadores mais baixo na precedência são os operadores de nomeação. Ver o diagrama de precedência no Dia 3 lição de um remais fresco na precedência de todos os operadores.

Condicionais de switch

Uma prática de programação comum em qualquer língua deve testar uma variável contra algum valor, e se não combinar com aquele valor, para testá-lo novamente contra um valor diferente, e se não combinar com aquele ainda para fazer outro teste, e assim por diante até que combine com o resultado direito. Usando só afirmações de if, isto pode ficar pesado, dependendo de como se formata e quantas opções diferentes tem de testar. Por exemplo, poderia terminar com o grupo de afirmações de if algo como isto ou mais longo:

if (oper == '+')
  addargs(arg1, arg2);
else if (oper == '-')
   subargs(arg1, arg2);
else if (oper == '*')
   multargs(arg1, arg2);
else if (oper == '/')
   divargs(arg1, arg2);

Esta forma da afirmação de if chama-se um if aninhado porque cada afirmação de else à sua vez ainda contém outro if, e assim por diante, até que todos os testes possíveis se tenham feito.

Muitas línguas têm uma versão de estenografia do if aninhado que é (um tanto) mais fácil ler e lhe permite agrupar os testes e ações. Chamado um switch ou afirmação de case, em Java chamou switch e comporta-se como faz em C:

switch (test) {
    case valueOne:
      resultOne;
      break;
    case valueTwo:
      resultTwo;
      break;
    case valueThree:
      resultThree;
      break;
    ...
    default: defaultresult;
}

Na afirmação de switch, o teste (uma variável ou expressão que avalia a um byte, char, short ou int) compara-se com cada um dos valores de caso (valueOne, valueTwo, e assim por diante) à sua vez. Se um jogo se encontrar, a afirmação (ou afirmações) depois que o teste se realiza. Se nenhum jogo se encontrar, a afirmação de default realiza-se. O default é opcional, portanto se não houver um jogo em nenhum dos casos e default não existe, a afirmação de switch conclui sem fazer algo.

Observe que a limitação significante do switch em Java é que os testes e os valores podem ser tipos primitivos só simples (e logo tipos só primitivos que são automaticamente castables a int). Não pode usar tipos primitivos maiores (long, float), cadeias ou outros objetos dentro de um switch, nem pode testar para qualquer relação outra do que a igualdade simples. Isto limita a utilidade de switch; if aninhado s pode trabalhar para qualquer espécie do teste em qualquer tipo.

Aqui está um exemplo simples de uma afirmação de switch semelhante ao if aninhado mostrado antes:

switch (oper) {
    case '+':
        addargs(arg1, arg2);
        break;
    case '-':
        subargs(arg1, arg2);
        break;
    case '*':
        multargs(arg1, arg2);
        break;
    case '/':
        divargs(arg1, arg2);
        break;
 }

Há duas coisas a estar sabendo neste exemplo: O primeiro é que depois de cada caso, pode incluir uma afirmação de resultado única ou tanto quanto precisa. Diferentemente de com if, não precisa de rodear múltiplas afirmações de tiras para ele para trabalhar. A segunda coisa a observar sobre este exemplo é a afirmação de break incluída no fim de cada caso. Sem o intervalo explícito, uma vez um jogo faz-se, as afirmações para aquele jogo (e também todas as afirmações além disso abaixo no switch de todos os outros casos) se realizam até um break ou o fim do switch encontra-se. Em alguns casos, isto pode ser exatamente o que quer fazer, mas na maioria dos casos, quererá assegurar-se para incluir o break para que só as afirmações quer executar-se se realizem de fato (intervalo, sobre o qual aprenderá na seção "Que se liberta de Laços", execução de paradas no ponto atual e saltos ao código do lado de fora do seguinte suporte de forma triangular final (})).

Um uso prático de permitir a um switch continuar processando afirmações depois de um jogo encontra-se ocorre quando quer que múltiplos valores combinem às mesmas afirmações. Neste exemplo, pode usar múltiplas linhas de caso sem resultado, e o switch realizará a primeira afirmação que encontra. Por exemplo, na seguinte afirmação de switch, a cadeia "x is an even number." imprime-se se x tiver um valor de 2, 4, 6 ou 8. Todos outros valores de x imprimem a cadeia "x is an odd number.":

switch (x) {
    case 2:
    case 4:
    case 6:
    case 8:
       System.out.println("x is an even number.");
       break;
    default: System.out.println("x is an odd number.");
}

A listagem 5.3 ainda mostra outro exemplo de um switch. Esta classe, chamada NumberReader, converte valores inteiros nos seus equivalentes de palavra ingleses reais usando um método chamado convertIt().


A listagem 5.3. A classe de NumberReader.
 1: class NumberReader {
 2:
 3:    String convertNum(int val) {
 4:       switch (val) {
 5:          case 0: return "zero ";
 6:          case 1: return "one ";
 7:         case 2: return "two ";
 8:          case 3: return "three ";
 9:          case 4: return "four ";
10:         case 5: return "five ";
11:         case 6: return "six ";
12:         case 7: return "seven ";
13:          case 8: return "eight ";
14:          case 9: return "nine ";
15:          default: return " ";
16:       }
17:   }
18:
19:    public static void main (String args[]) {
20:      NumberReader n = new NumberReader();
21:      String num = n.convertNum(4) + n.convertNum(1)  + n.convertNum(5);
22:      System.out.println("415 converts to " + num);
23:   }
24:}

415 converts to four one five

Análise
O coração deste exemplo é, naturalmente, a afirmação de comutador principal no meio do converso Num () método em linhas 4 para 16. Esta afirmação de comutador toma o argumento de número inteiro que se passou no converso Nm () e, quando encontra um jogo, devolve o valor de cadeia apropriado. (Observe que este método se define para devolver uma cadeia ao contrário de outros métodos que definiu até este ponto, que não devolveu nada. Aprenderá mais sobre isto amanhã.)

Assim, onde estão as afirmações de break? Não precisa deles aqui porque usa return em vez disso. return é semelhante a break exceto que se liberta da definição de método inteira e devolve um valor único. Novamente, aprenderá mais sobre isto amanhã quando aprende todos sobre como definir métodos.

Neste ponto viu provavelmente bastantes métodos de main() para saber o que está acontecendo, mas vamos examinar este rapidamente.

A linha 20 cria um novo exemplo da classe de NumberReader.

A linha 21 define uma cadeia chamada num que será a concatenação dos valores de cadeia de três números. Cada número converte-se usando uma chamada ao método de convertNum().

Finalmente, a linha 22 imprime o resultado.

Laços de for

O laço de for, como em C, repete uma afirmação ou o bloco de afirmações até que uma condição se combine. os laços de for usam-se frequentemente para iterações simples nas quais repete um bloco de afirmações um certo número de tempos e logo para, mas pode usar laços de for para quase qualquer espécie do laço.

O laço de for em Java parece rudemente a isto:

for (initialization; test; increment) {
    statements;
}

A partida do laço de for tem três partes:

A parte de afirmação do laço de for é as afirmações que se realizam cada vez quando o laço repete. Tal como com if, só pode incluir uma afirmação, embora um bloco trabalhe somente perfeito também.

Lembre-se do exemplo na seção em tabelas onde disse que repetir sobre os conteúdos de uma tabela se faz normalmente com um laço? Aqui está um exemplo de um laço de for que faz somente que - inicializa todos os valores de uma tabela de String a cadeias nulas:

String strArray[] = new String[10]; \\ the array
int i; // loop index

for (i = 0; i < strArray.length; i++)
    strArray[i] = "";

Neste exemplo, o I variável guarda a pista do número de vezes o laço ocorreu; também faz um índice conveniente da própria tabela. Aqui, começamos o laço de for com um índice de I. O teste de quando o laço de for terminará consiste em se o índice atual é menos do que o comprimento da tabela (uma vez que o índice é maior do que a tabela, deve parar), e o incremento simplesmente deve acrescentar 1 ao índice cada vez. Então, para cada laço pode pôr uma cadeia nula ("") na tabela na fenda dada.

Alguma das partes do laço de for pode ser afirmações vazias; isto é, simplesmente pode incluir um ponto-e-vírgula sem expressão ou afirmação, e aquela parte do laço de for vai se ignorar. Observe que se realmente usar uma afirmação nula no seu laço de for, deveria inicializar ou incrementar qualquer variável de laço ou índices de laço você mesmo em outro lugar no programa.

Também pode ter uma afirmação vazia para o corpo do seu laço de for, se tudo que quer fazer estiver na primeira linha daquele laço. Por exemplo, aqui está aquele que encontra o primeiro número primo mais alto do que 4.000 (chama um método chamado notPrime(), que terá teoricamente um modo de compreender isto):

for (i = 4001; notPrime(i); i += 2)
    ;

Observe que um erro comum em C que também ocorre em Java deve pôr acidentalmente um ponto-e-vírgula depois da primeira linha do laço de for:

for (i = 0; i < 10; i++);
    System.out.println("Loop!");

Como o primeiro ponto-e-vírgula termina o laço em uma afirmação vazia, o laço não faz de fato nada. A função de println() só vai se imprimir uma vez porque é de fato do lado de fora do laço de for inteiramente. Procure não fazer este erro nos seus próprios programas Java.

Para terminar laços de for, vamos reescrever aquele exemplo com os nomes da seção de tabela. O exemplo original é longo e repetitivo e só trabalha com uma tabela quatro elementos muito tempo. Esta versão, mostrada na Listagem 5.4, é mais curta e mais flexível (mas devolve a mesma produção).


A listagem 5.4. Uma tabela modificada testa com laços.
 1: class NamesLoop {
 2:
 3:    String[] firstNames = { "Dennis", "Grace", "Bjarne", "James" };
 4:    String[] lastNames = new String[firstNames.length];
 5:
 6:    void printNames() {
 7:      for (int i = 0; i < firstNames.length; i++)
 8:          System.out.println(firstNames[i] + " " + lastNames[i]);
 9:    }
10:
11:   public static void main (String args[]) {
12:      ArrayTest a = new ArrayTest();
13:       a.printNames();
14:       System.out.println("----------");
15:       a.lastNames[0] = "Ritchie";
16:       a.lastNames[1] = "Hopper";
17:      a.lastNames[2] = "Stroustrup";
18:       a.lastNames[3] = "Gosling";
19:
20:      a.printNames();
21:}
22:}

Dennis null
Grace null
Bjarne null
James null
----------
Dennis Ritchie
Grace Hopper
Bjarne Stroustrup
James Gosling

Análise
A única diferença entre este exemplo e a Listagem 5.1 está no método de printNames(). Em vez de atravessar as fendas de tabela um por um, este exemplo usa um laço de for para repetir pela tabela uma fenda de uma vez, parando no elemento último na tabela. Usar um laço mais de uso geral para repetir sobre uma tabela permite para usar printNames() para qualquer tabela de qualquer tamanho e ainda o ter imprime todos os elementos.

while e laços de do

Finalmente, há while e os laços de do. while e os laços de do, como laços de for, repetem a execução de um bloco do código de Java até que uma condição específica se encontre. Se usa um laço de for, um while, ou um do é pela maior parte uma matéria do seu estilo de programação.

while e os laços de do são exatamente o mesmo como em C e C ++ exceto que as suas condições de experiência devem ser booleans.

Laços de while

O laço de while usa-se para repetir uma afirmação ou o bloco de afirmações enquanto uma determinada condição é true. os laços de while parecem a isto:

while (condition) {
    bodyOfLoop;
}

O condition é um teste booleano porque está em construções de for e o if. Se o teste devolver true, o laço de while realiza as afirmações em bodyOfLoop e logo testa a condição novamente, repetindo-se até que a condição seja false. Mostrei o laço de while aqui com uma afirmação de bloco porque se usa o mais comumente, embora possa usar uma afirmação única no lugar do bloco.

A listagem 5.5 mostra um exemplo de um laço de while que copia os elementos de uma tabela de números inteiros (em array1) a uma tabela de float s (em array2), lançando cada elemento a um float quando vai. Um proveito é que se algum dos elementos na primeira tabela for 0, o laço sairá imediatamente naquele ponto.


A listagem 5.5. laços de while para copiar elementos de tabela.
 1: class CopyArrayWhile {
 2:   public static void main (String args[]) {
 3:       int[] array1 = { 5, 7, 3, 6, 0, 3, 2, 1 };
 4:       float[] array2 = new float[array1.length];
 5:
 6:        System.out.print("array1: [ ");
 7:       for (int i = 0; i < array1.length; i++) {
 8:          System.out.print(array1[i] + " ");
 9:        }
10:       System.out.println("]");
11:
12:       System.out.print("array2: [ ");
13:       int count = 0;
14:       while ( count < array1.length && array1[count] != 0) {
15:              array2[count] = (float) array1[count];
16:              System.out.print(array2[count++] + " ");
17:      }
18:        System.out.println("]");
19:    }
20:}

array1: [ 5 7 3 6 0 3 2 1 ]
array2: [ 5 7 3 6 ]

Fiz todo o trabalho aqui em main() para fazer coisas mais curto. Aqui está o que está acontecendo aqui:

Linhas 3 e 4, declare as tabelas; array1 é uma tabela de int s, que inicializei a alguns números convenientes. array2 ou float s, é o mesmo comprimento que array1, mas não tem valores iniciais.

As linhas 6 para 10 são com objetivos de produção; simplesmente repetem por array1 usando um laço de for para imprimir os seus valores.

As linhas 13 para 17 são onde o material interessante acontece. Este ramo de afirmações ambos destina os valores de array2 (convertendo os números em bóias ao longo da tabela) e imprime-o ao mesmo tempo. Começamos com uma variável de count, que guarda a pista dos elementos de índice de tabela. O teste no laço de while guarda a pista das duas condições do existente o laço, onde aquelas duas condições ficam sem elementos em array1 ou encontrando um 0 em array1 (lembre-se, foi parte da descrição original do que este programa faz). Podemos usar o && condicional lógico para guardar a pista do teste; lembre-se de que && se assegura que ambas as condições são true antes que a expressão inteira seja true. Se qualquer for false, a expressão devolve false e as saídas de laço.

Assim, o que continua neste determinado exemplo? A produção mostra que quatro primeiros elementos em array1 se copiaram a array2, mas houve um 0 no meio que parou o laço de ir mais longe. Sem o 0, array2 deve terminar com mesmo assim elementos como array1.

Observe que se o teste de laço de while for inicialmente false a primeira vez se testa (por exemplo, se o primeiro elemento naquela primeira tabela for 0), o corpo do laço de while nunca se realizará. Se tiver de realizar o laço pelo menos uma vez, pode fazer uma de duas coisas:

Laços de do...while

O laço de do é como um laço de while, exceto que do realiza uma afirmação dada ou bloco até que a condição seja false. A diferença principal é que os laços de while testam a condição antes da rotação, permitindo que o corpo do laço nunca realizará se a condição for false a primeira vez quando testa-se. os laços de do dirigem o corpo do laço pelo menos uma vez antes de testar a condição. os laços de do parecem a isto:

do {
    bodyOfLoop;
} while (condition);

Aqui, a parte de bodyOfLoop é as afirmações que se realizam com cada iteração. Mostra-se aqui com uma afirmação de bloco porque se usa o mais comumente aquele caminho, mas pode substituir pelas tiras por uma afirmação única como pode com outros construtos de fluxo do controle. A condição é um teste booleano. Se devolver true, o laço dirige-se novamente. Se devolve false, saídas de laço. Tenha em mente que com laços de do, o corpo do laço pelo menos realiza uma vez.

A listagem 5.6 mostra um exemplo simples de um laço de do que imprime uma mensagem cada vez quando o laço repete (10 vezes, para este exemplo):


A listagem 5.6. Um laço de do simples.
 1: class DoTest {
 2:    public static void main (String args[]) {
 3:      int x = 1;
 4:
 5:      do {
 6:        System.out.println("Looping, round " + x);
 7:        x++;
 8:      } while (x <= 10);
 9:    }
10: }

Looping, round 1
Looping, round 2
Looping, round 3
Looping, round 4
Looping, round 5
Looping, round 6
Looping, round 7
Looping, round 8
Looping, round 9
Looping, round 10

Libertando-se de laços

Em todos os laços (for, while e do), o laço termina quando a condição para a qual testa se encontra. O que acontece se algo ímpar ocorrer dentro do corpo do laço e quer sair o laço cedo? Para isto, pode usar palavras-chave de continue e o break.

Já viu break como parte da afirmação de switch; para a execução do switch, e o programa continua. A palavra-chave de break, quando usado com um laço, faz a mesma coisa - imediatamente para a execução do laço atual. Se tenha aninhado laços dentro de laços, a execução apanha no seguinte laço exterior; de outra maneira, o programa simplesmente continua realizando a seguinte afirmação depois do laço.

Por exemplo, tome aquele laço de while que copiou elementos de uma tabela de número inteiro em uma tabela de bóias até o fim da tabela ou até que um 0 se consiga. Pode testar em vez disso para aquele último caso dentro do corpo do while e logo usar um break para sair o laço:

int count = 0;
while (count < array1.length) {
    if (array1[count] == 0) {
        break;
    }
    array2[count] = (float) array1[count++];
}

continue é semelhante a break exceto que em vez da de parada execução do laço inteiramente, o laço começa acabado no momento da seguinte iteração. Para do e laços de while, isto significa que a execução do bloco começa novamente; para laços de for, o incremento e as expressões de experiência avaliam-se e logo o bloco realiza-se. continue é útil quando quer a elementos de caso especial dentro de um laço. Com o exemplo prévio de copiar uma tabela ao outro, pode testar para se o elemento atual é 0 e reinicie o laço se o encontrar para que a tabela resultante nunca contenha o zero. Observe que porque omite elementos na primeira tabela, agora tem de guardar a pista de dois balcões de tabela diferentes:

int count1 = 0;
int count2 = 0;
while (count < array1.length) {
    if (array1[count1] == 0)  {
       continue;
        count1++
    }
    array2[count2++] = (float)array1[count1++];
}

Laços etiquetados

Tanto break como continue podem ter uma etiqueta opcional que diz Java onde estalar a. Sem uma etiqueta, break pula do lado de fora do laço mais próximo (a um laço de cerrado ou à seguinte afirmação do lado de fora do laço), e continue reinicia o laço de cerrado. A utilização etiquetou break s e continue s, pode estalar a pontos específicos do lado de fora de laços aninhados ou continuar um laço do lado de fora do laço atual.

Para usar um laço etiquetado, acrescente a etiqueta antes da parte inicial do laço, com uns dois pontos entre eles. Então, quando usa break ou continue, acrescente o nome da etiqueta depois da própria palavra-chave:

out:
    for (int i = 0; i <10; i++) {
        while (x < 50) {
            if (i * x == 400)
                break out;
            ...
        }
        ...
    }

Neste fragmento do código, a etiqueta out etiqueta o laço exterior. Então, tanto dentro do for como dentro dos laços de while, quando uma determinada condição se encontra, um break faz que à execução se liberte de ambos os laços e continue realizando qualquer código depois de ambos os laços.

Aqui está outro exemplo: O programa mostrado na Listagem 5.7 contém um laço de for aninhado. Dentro do laço íntimo, se os valores somados dos dois balcões é maior do que 4, amba a saída de laços ao mesmo tempo.


A listagem 5.7. Um exemplo de laço etiquetado.
 1: class LabelTest {
 2:    public static void main (String arg[]) {
 3:
 4:      foo:
 5:      for (int i = 1; i <= 5; i++)
 6:        for (int j = 1; j <= 3; j++) {
 7:           System.out.println("i is " + i + ", j is " + j);
 8:           if (( i + j) > 4)
 9:           break foo;
10:        }
11:      System.out.println("end of loops");
12:    }
13:}

i is 1, j is 1
i is 1, j is 2
i is 1, j is 3
i is 2, j is 1
i is 2, j is 2
i is 2, j is 3
end of loops

Como pode ver, o laço repetido até a soma de i e j foi maior do que 4, e logo ambos os laços saíram atrás ao bloco exterior e a mensagem final imprimiu-se.

Sumário

Hoje aprendeu aproximadamente três tópicos principais que bastante muitas vezes usará mais provavelmente nos seus próprios programas Java: tabelas, condicionais e laços.

Aprendeu como declarar uma variável de tabela, criar e destinar um objeto de tabela àquela variável, e acesso e elementos de modificação dentro daquela tabela.

Os condicionais incluem o if e afirmações de switch, com as quais pode bifurcar-se a partes diferentes do seu programa baseado em um teste booleano.

Finalmente, aprendeu sobre o for, while e laços de do, cada um dos quais lhe permitem realizar uma porção do seu programa repetidamente até que uma condição dada se encontre.

Agora que aprendeu o pequeno material, tudo que isto se deixa deve revisar as questões maiores de declarar classes e criar métodos dentro dos quais os exemplos daquelas classes podem comunicar-se um com outro chamando métodos. Venha para deitar cedo esta noite, porque amanhã vai ser um passeio selvagem.

Perguntas e Respostas

Q:
Se as tabelas forem objetos, e usa new para criá-los, e têm um comprimento de variável de exemplo, onde está a classe de Array? Não o vi nas bibliotecas de classe de Java.
A:
As tabelas implementam-se espécie de esquisitamente em Java. A classe de Array constrói-se automaticamente quando o seu programa Java corre; Array fornece a armação básica para tabelas, inclusive a variável de length. Adicionalmente, cada tipo primitivo e o objeto têm uma subclasse implícita de Array que representa uma tabela daquela classe ou objeto. Quando cria um novo objeto de tabela, pode não ter uma classe real, mas comporta-se como se faça.
Q:
Quando cria uma tabela, tem de dar-lhe o número de fendas que a tabela tem. O que acontece se se tornar a meia distância pelo seu programa e ficou sem fendas na tabela? A tabela torna-se maior automaticamente?
A:
Não, as tabelas ficam o mesmo tamanho durante a sua existência. E, como observei na parte desta lição em tabelas, não pode acessar fendas do lado de fora dos limites da tabela, acrescentando que os então extra elementos a uma tabela cheia causarão um erro.

Assim, o que faz se uma tabela for cheia? Tem de fazê-lo o caminho difícil: Crie uma nova tabela isto é maior do que o inicial e copie todos os elementos da velha tabela ao novo.

Opcionalmente, pode usar uma estrutura de dados outra do que uma tabela se esperar ter números de elementos largamente variados na tabela. A classe de Vector, parte do pacote de java.util, é uma coleção growable que pode usar no lugar de uma tabela.

Q:
Java tem goto s?
A:
A língua de Java define a palavra-chave goto, mas não se usa atualmente para nada. Em outras palavras, sem Javas não tem goto s.
Q:
Declarei uma variável dentro de uma afirmação de bloco para um if. Quando o if se fez, a definição daquela variável desapareceu. Onde foi?
A:
Em termos técnicos, as afirmações de bloco formam um novo alcance lexical. O que isto significa é que se declarar uma variável dentro de um bloco, só é visível e usável dentro daquele bloco. Quando o bloco termina de realizar, todas as variáveis que declarou vão-se.

É uma boa ideia de declarar a maioria das suas variáveis no bloco externo no qual serão necessários normalmente em cima de uma afirmação de bloco. A exceção poderia ser variáveis muito simples, como balcões de índice em laços de for, onde declará-los na primeira linha do laço de for é um atalho fácil.

Q:
Porque não pode usar switch com cadeias?
A:
As cadeias são objetos e switch em trabalhos de Java só dos tipos primitivos byte, char, short e int. Para comparar cadeias, tem de usar aninhou if s, que permitem testes de expressão mais gerais, inclusive a comparação de cadeia.
Q:
Parece-me que muitos laços de for podem escrever-se como laços de while, e vice-versa.
A:
Verdadeiro. O laço de for é de fato um caso especial de while que lhe permite repetir um laço um número de vezes específico. Pode fazer tão facilmente isto com um while e logo incrementar um balcão dentro do laço. Qualquer trabalhos igualmente bem. Isto é pela maior parte somente uma pergunta de programar o estilo e a escolha pessoal.