Controle de Fluxo Marco Antonio Introdução • Controle de fluxo inclui as seguintes situações: – – – – Declarações de if e switch Laços com break e continue Controle de exceções assent Identação if (exam.done()) if (exam.getScore() < 0.61) System.out.println("Try again."); else System.out.println("Java master!"); Teste public class Teste { public static void main(String[] args) { byte x = 10; if (x < 0) { if (x == 11) { System.out.println("x é igual 11"); } else if (x == x--) { System.out.println("x é menor que 11"); } } else System.out.println("x não é menor que 0"); } } Resultado • X não é menor que 10 Teste public class Teste { public static void main(String[] args) { byte x = 10; if (x <= x--) { if (x == 11) { System.out.println("x é igual 11"); } else if (x == x--) { System.out.println("x é menor que 11"); } } else System.out.println("x não é menor que 0"); } } Resultado • x é menor que 11 Teste public class Teste { public static void main(String[] args) { byte x = 10; if (x <= --x) { if (x == 11) { System.out.println("x é igual 11"); } else if (x == x--) { System.out.println("x é menor que 11"); } } else System.out.println("x não é menor que 0"); } } Resultado x não é menor que 0 Teste public class Teste { public static void main(String[] args) { byte x = 10; if (x < 0) if (x == 11) { System.out.println("x é igual 11"); } else if (x == x--) { System.out.println("x é menor que 11"); } else System.out.println("x não é menor que 0"); } } Resultado • Não imprime nada... Teste public class Teste { public static void main(String[] args) { boolean b = false; if (b = true) { System.out.println("b é verdadeiro"); } else { System.out.println("b é false"); } } } Teste public class Teste { public static void main(String[] args) { int x = 0, y = 0, a = 1, z = 3; if (x > 3) y = 2; z += 8; a = y + x; } } Switch • Chaveamento de valores Teste public class Teste { public static void main(String[] args) { byte x = 3; switch (x) { case 1: System.out.println("x vale 1"); break; case 2: System.out.println("x vale 2"); break; default: System.out.println("x é maior que 2"); break; } } } Resultado • x é maior que 2 Teste public class Teste { public static void main(String[] args) { byte x = 1; switch (x) { case 1: System.out.println("x vale 1"); break; case 2: System.out.println("x vale 2"); default: System.out.println("x é maior que 2"); break; } } } Resultado • • • • x vale 1 Altere o x para 2. O que acontece? Atenção para o break. Teste public class Teste { public static void main(String[] args) { byte x = 2; switch (x) { case 1: System.out.println("x vale 1"); break; default: System.out.println("x é maior que 2"); break; case 2: System.out.println("x vale 2"); } } } Teste public class Teste { public static void main(String[] args) { byte x = 1; switch x { case 1: System.out.println("x vale 1"); break; case 2: System.out.println("x vale 2"); default: System.out.println("x é maior que 2"); break; } } } Teste int x = 10; switch (x) { case 1: { ... } case 2: { ... } case 1: { ... } } // Erro de compilação: duplicate case label Teste long x = 100; switch (x) { // Erro de compilação: possible loss of precision case 1: { ... } case 2: { ... } } • Mude o tipo de x para String. Teste final int op1 = 1; final int op2 = 2; int op3 = 3; int opcao = 2; switch (opcao) { case op1: { ... } // ok, op1 é final case op2: { ... } // ok, op2 é final case op3: { ... } // Erro de compilação: constant expression required default: { ... } } Teste int x = 1; switch (x) { case 1: System.out.println("1"); default: System.out.println("default"); case 2: System.out.println("2"); case 3: System.out.println("3"); case 4: System.out.println("4"); } Observações • Não tem break, imprime tudo. Teste public class Teste { public static void main(String[] args) { int x = 3; switch (x) { case 1: System.out.println("1"); default: System.out.println("default"); case 2: System.out.println("2"); case 3: System.out.println("3"); case 4: System.out.println("4"); } } } Observações • Imprime 3 e 4. Teste public class Teste { public static void main(String[] args) { final int x = 2; for (int i = 0; i < 2; i++) { switch (i) { case x - 1: System.out.print("1 "); default: System.out.print("def "); case x: System.out.print("2 "); break; case x + 1: System.out.print("3 "); } } } } Qual a solução • a) Não será compilado b) def 2 def 2 1 c) def 2 1 def 2 d) def 2 1 def 1 e) def 1 2 def 1 Teste public class Teste { public static void main(String[] args) { //int s = 9; for (int i = 0, s = 10; i < 10; i++) { System.out.println("" + (s + i)); } } } Teste public class Teste { public static void main(String[] args) { for (int i = 0; i < 10 | (i % 2) == 0; i++) { System.out.println("" + i); } } } Atenção • Quando a condição for falsa o loop acaba. Teste public class Teste { public static void main(String[] args) { int x = 0; for (int i = 0; i < 10; i++) { x = i; if (i == 3) break; System.out.println("i: " + x); } } } Break • O loop acaba depois do break. Continue • Altere o break para continue; • O que acontece? • O loop passar para o próximo i. Teste public class Teste { public static void main(String[] args) { int x,i = 0; for (;;) { x = i; if (i == 3) continue; System.out.println("i: " + x); } } } Teste public class Teste { public static void main(String[] args) { for (int x = 0; (x > 5), (y < 2); x++) { } } } Regra • O que devemos lembrar é que não podemos ter duas expressões de teste. Rótulos public class Teste { public static void main(String[] args) { for (int i = 10; i < 20; i++) { aqui: for (int j = 1; j < 2; j++) { if (i % 2 == 0) continue aqui; //Números pares System.out.println(i); } } } } Exceções • O tratamento de exceções (não de erros) em java é bastante completo, permitindo um bom refinamento da aplicação. Try/catch block try { // primeira linha vigiada } catch (Exception e) { // primeira linha que será executada caso haja um exceção do tipo Exception } finally { // bloco que será executado, havendo ou não uma exceção (sempre!) } Formas try { } catch (MyException e) { } • ? Formas try { } • ? Formas try { } finally { } • ? Erros import java.io.*; public class Erros { public static void main(String[] args) { metodoDoMal(); } public static void metodoDoMal() { try { throw new IOException("eu fiz um erro"); } catch (IOException e) { // código que solucionará o problema } } } Erros package tjdf.sistj.assuntodaclassificacao.negocio; import java.io.*; public class Erros { public static void main(String[] args) { metodoDoMal(); //Qual o problema? } public static void metodoDoMal() throws IOException { throw new IOException("eu fiz um erro"); } } Erros import java.io.*; import java.awt.print.*; public class Teste { public static void main(String[] args) { try { metodoDoMal(); } catch (IOException e) { } catch (PrinterException p) { } } static void metodoDoMal() throws IOException, PrinterException { metodoPiorAinda(); } static void metodoPiorAinda() throws PrinterException { } } //Tudo certo Erros import java.io.*; import java.awt.print.*; public class Teste { public static void main(String[] args) { try { metodoDoMal(); } catch (IOException e) { } } static void metodoDoMal() throws IOException { metodoPiorAinda(); //Aqui temos um problema... } static void metodoPiorAinda() throws PrinterException { } } RealData import java.io.*; public class ReadData { public static void main(String args[]) { try { RandomAccessFile raf = new RandomAccessFile("myfile.txt", "r"); byte b[] = new byte[1000]; raf.readFully(b, 0, 1000); } catch (IOException e) { System.err.println("IO Error"); System.err.println(e.toString()); e.printStackTrace(); } catch (FileNotFoundException e) { System.err.println("File not found"); System.err.println(e.getMessage()); e.printStackTrace(); } } } Hierarquia de classes • A sequência deve ser sempre da exceção mais especifica para a mais genérica, ou seja: a mais específica é FileNotFoundException, e a mais genérica é IOException. Principais exceções • ArrayIndexOutOfBoundsException, ClassCastException, NullPointerException, ExceptionInitializerError, StackOverflowError, NoClassDefFoundError. • IllegalArgumentException, IllegalStateException, NumberFormatException, AssertionError. Assertivas • Use assertiva para validar argumentos em métodos privados – Como a visibilidade é privada, você consegue detectar erros. • Use assertiva sem condição em um bloco que presuma que nunca seja alcançado. – Se você tem um bloco que nunca seria alcançado, você pode usar uma assert false, pois assim saberia se em algum momento esse bloco está sendo alcançado. • Lançar um AssertionError explicitamente • Se um bloco switch não tiver uma instrução default, adicionar uma assertiva é considerado uma boa prática Formas Default assert ( i < 0 ); Simples assert ( i > 0 ) : "Valor do i é "+i; assert(x == 1) : aReturn(); Erros comuns • assert(x == 1) : ; • assert(x == 1) : metodoSemReturn(); • assert(x == 1) : ValidAssert va; Como não usar • Nunca manipula um AssertionError – Não use um catch e manipula um erro de assertiva • Não use assertiva para validar argumentos em métodos públicos – Você não pode garantir nada em métodos público, portanto usar assertiva nesse caso, não é uma boa prática • Não use assertiva para validar argumento da linha de comando – Isso é uma particularidade de um método público, mas segue a mesma regra • Não use assertivas que possam causar efeitos colaterais – Você não pode garantia que as assertivas sempre serão executadas, portanto o seu programa deve executar independentemente das assertivas, e nunca de forma diferente simplesmente porque as assertivas foram ativadas. Como habilitar • • • • java –ea / java -enableassertion // habilita assertion java -da / java -disableassertion // desabilita assertion java -ea:br.com.Atimo // habilita para o pacoto br.com.Atimo java -ea -das // habilita assertion em âmbito geral e desabilita nas classes do systema • java -esa // habilita nas classes do sistema