Dúvidas a respeito de while

Olá:

Quero apresentar-lhes um pequeno programa e fazer umas considerações sobre ele. Num loop while infinito ele aprsenta um diálogo perguntando se quer continuar ou não. Se clicar em “sim” o loop continua; se clicar em “não” ou em “cancela” ele sai do loop. Segue-se o código:

import javax.swing.JOptionPane;

public class TestaReturn {

    public static void main(String args[]) {
        while(true){
            int opcao = JOptionPane.showConfirmDialog(null, "Continua?");
            if((opcao == JOptionPane.NO_OPTION) ||
            (opcao == JOptionPane.CANCEL_OPTION)) {
                 System.exit(0); // linha 1
                 //break;        // linha 2
                 //return;       // linha 3
            }
        }
        //System.out.println("Saiu do while"); // Aviso
        //System.exit(0); // Linha A
        //return;         // Linha B
    }
}

:arrow: Do jeito como está, o programa compila normalmente e termina normalmente quando sai do loop. Mas sem imprimir o aviso.
:arrow: Se a linha 1 ou a 3 estiverem descomentadas e se o aviso e/ou as linhas A ou B estiverem descomentadas o compilador (seja javac ou jikes) solta o seguinte erro: “unreachable statement”.
:?: Como o Compilador pode determinar o que está ou não “unreachable”? Ele verifica pelas ocorrências de “System.exit(0)” ou de “return” e determina que o que vier depois não terá efeito?
:arrow: Se a linha 2 e o aviso estiverem descomentados, a compilação é normal. Ao sair do while, o aviso é impresso. Mas o programa não é concluído. Tenho que terminá-lo na “marra”. Mesmo se descomentar a linha B isso acontece. Só com a linha A descomentada (e a B comentada) o programa é terminado normalmente.
:?: Alguém tem idéia de como concluir o programa normalmente sem ter que “forçar a barra” com System.exit(0)?

Grato,

Eu não sei dizer porque, mas o código a seguir faz a mesma coisa (sem usar Swing) e finaliza o programa normalmente:

import java.io.*;

public class TestaReturn { 

    public static void main(String args[]) throws Exception { 
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

        while(true){ 
            System.out.print("Continua (1=SIM,2=NAO)? ");
            int opcao = Integer.parseInt(in.readLine());

            if (opcao == 2) { 
                 break;
            } 
        } 

        System.out.println("Saiu do while"); // Aviso 
    } 
}

Se alguém puder explicar, seremos gratos!
Valeu!

Cara,

Tente usar uma variável boolean que é testada no while e que ao ser pedido o encerramento do loop seja setada como false. Quando o while for testar a condição novamente verá que é falsa e sairá do while sem forçar a barra e executando o resto do código:

[code]import javax.swing.JOptionPane;

public class TestaReturn {

public static void main(String args[]) { 
    boolean teste = true
    while(teste){ 
        int opcao = JOptionPane.showConfirmDialog(null, "Continua?"); 
        if((opcao == JOptionPane.NO_OPTION) || 
        (opcao == JOptionPane.CANCEL_OPTION)) { 
             teste = false;
        } 
    } 
    System.out.println("Saiu do while"); // Aviso 
    System.exit(0); // Linha A 
} 

}

[/code]

té mais…

Gustavo Guilherme BacK

Reparou que está usando System.exit(0) para terminar o programa? É isso que chamei de “forçar a barra”. O ideal não seria não usar este método?

Bem, praticamente o Caio matou o problema, esse código funciona :

import javax.swing.JOptionPane;

public class TestaReturn {

    public static void main(String args[]) {
        while (true) {
            int opcao = JOptionPane.showConfirmDialog(null, "Continua?");
            if ((opcao == JOptionPane.NO_OPTION)
                || (opcao == JOptionPane.CANCEL_OPTION)) {

                break; // quebra o loop 

            }
        }
        System.out.println("Saiu do while"); // Aviso 
        System.exit(0);
    }
}

Vamos as dúvidas :

Cuidado com o System.exit(0), pois ele termina a aplicação no momento que ele é invocado, na verdade ele não sai do loop (entre aspas), ele termina a aplicação, ele não imprime o aviso pois a linha do aviso está comentada e não pode ter código abaixo do System.exit(0), pois ele nunca será executado e o compilador vai reclamar.

Como disse, já que tem código abaixo do System.exit(0) o compilador reclama, pois esse trecho não será executado

Sim, só lembrando que o comando “return” sai de um método a partir do momento em que ele é chamado e o System.exit(0) termina a aplicação

Basta colocar o System.exit(0) na última linha do método main

Então isso significa que sempre que usar algum componente Swing (JOptioPane, JFrame, etc) sempre tenho que colocar um System.exit(int) no final. É isso?

Rafael,

Segundo o livro “Java - Como Programar, 3a. edição”, todo programa Java que utiliza uma interface gráfica deve ser encerrado com uma chamada ao método static exit da classe System. Infelizmente, ele não dá mais detalhes sobre isso.

Abraço,

Fico com a idéia do nosso colega… caiofilipini
Quando vc dá System.exit(0) dentro do while, o código fora dele nunca será executado pq ele não vai sair nunca do while, e quando o faz, é para terminar o programa… daí unreachable statement.

bem vc pode colocar o break dentro do while para sair dele (quando necessário) e executar os demais códigos e após a mensagem de “saiu do while” colocar o System.exit(0)… essa é uma forma de sair e imprimir a mensagem sem mudar a estrutura do seu código… (ou melhor, imprimir e sair… :smiley: )

porém a idéia de usar a variável boolean como teste no while tb é uma boa saída…

bom,

O código que eu apresentei também executa numa boa… e quanto ao System.exit(0) é a única forma que eu conheço de encerrar um programa corretamente…

Ó! meu código também tá certo aí, as o do caio ainda também está corretíssima…

Alguém conhece outra forma de encerrar um programa que não seja através do System.exit(int) ???

té mais…

Gustavo Guilherme BacK

Creio que a razão do System.exit(int) é que quando usamos Swing - seja um JFrame ou um JOptionPane - é que é criado um novo Thread. Quando é atingido o final do main(), o Thread principal é concluído, mas o Thread do Swing continua rodando. Daí para interromper somente com o System.exit(int). Por isso o programa escrito pelo caiofilipini terminava sem precisar de System.exit(int).
Esta é minha teoria. Alguem mais íntimo das entranhas do Java me corriga ou confime o que escrevi.

Grato,

Não é System.exit que faz com que o statement seja unreachable. Isso porque, acredito, o compilador não deve conhecer a implementação dos metodos e sim a parte “semantica” da linguagem.

Se fosse por causa do System.exit o codigo abaixo não compilaria.

public class Exit {
	public static void main(String[] args) {
		System.out.println("Entrou...");
		System.exit(0);
		System.out.println("Saiu...");
	}
}

Acho que o que acontece é o seguinte. Qualquer statement colocado depois de um loop infinito que não tenha uma condição de parada usando um break será unreachable. E isso o compilador pode prever.

Statements colocados imediatamente depois de return, continue, break e throw(esqueci algum?!) tambem serão unreachable. Acho que é isso. Quanto a ter que usar o System.exit para terminar o programa que usa swing, fico com a teoria do Rafael.