Upload
elenilson-vieira
View
3.123
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
Grupo de Estudos - SCJP
Controle de Fluxo
Exceções
Assertivas
Eduardo Silva
ufpb, junho de 2009
instruções ifFormato básico:
if (expressãoBooleana) {
...println(“entrou no if”);
}
if (new Boolean(true) && !ehMentira()) {
...println("no if");
}
if (a == b & b > c || c != d && d <= a) {
...println("dentro");
}
else e else-ifif (nota > 7) {
...println(“maior”);
} else {
...println(“não-maior”);
}
if (peso < 40) {
...println(“vôou”);
} else if (peso < 55) {
...println(“magro”);
} else if (peso < 65) {
...println(“quase”);
} else {
...println(“beleza”);
}
if true {
...println(“it's true”);
}
if (a < b) {
...println("um");
}
if (c > b) {
...println("dois");
} else {
...println("tres");
} else if (true) {
...println("quatro");
}
avisosif (ehVerdade())
if (!ehVerdade())
...println(“paradoxo”);
else
...println(“pior que é verdade”);
int verum = 1, falsum = 0;
// inválidos:
if (verum)
if (verum == true)
if (1)
if (falsum == false)
// válidos:
if (verum == 1)
if (falsum == 0)
� casado com o último if
if (nota > 7)
...println(“passou”);
...println(“deu beleza”);
instrução switchchar ch = 'a';
if (ch == 'c') {
...println(“cê”);
} else {
if (ch == 'b') {
...println(“bê”);
} else {
if (ch == 'a') {
...println(“á”);
} else {
...println(“outra”);
}
}
}
char ch = 'a';
switch (ch) {
case 'c':
...println(“cê”);
break;
case 'b':
...println(“bê”);
break;
case 'b':
...println(“á”);
break;
default:
...println(“outra”);
}
+ switchlong l = 11;
switch (l) { }
� a expressão do switch só avaliará enums e (valores e
variáveis que puderem ser implicitamente convertidos num int)
final int x = 0, a = 1, b;
b = 2;
switch (x) {
case a:
case b:
}
� o argumento do case tem que ser uma constante em tempo
de compilação (variável literal ou final, expressão constante,
incluindo enum)
+ switchlong l = 11;
switch (l) { } // possible lost of precision
� a expressão do switch só avaliará enums e (valores e
variáveis que puderem ser implicitamente convertidos num int)
final int x = 0, a = 1, b;
b = 2;
switch (x) {
case a:
case b: // constant expression required
}
� o argumento do case tem que ser uma constante em tempo
de compilação (variável literal ou final, expressão constante,
incluindo enum)
três erros de compilação:byte b = 22;
switch (b) {
case 22:
case (b < 23):
break;
case 128:
break;
case 22:
}
alguns detalhesbyte b = 22;
switch (b) {
case (b < 23): // imcompatible types
...println(“switch só testa igualdade”);
break;
case 128: // possible lost of precision
...println(“o compilador sabe que 128 não cabe num byte”);
break;
case 22: // o break é opcional
case 22: // duplicate case label
...println(“mesmo valor para dois cases”);
}
mais algunsswitch (new Integer(127)) {
case 127 { // faltou o “:”
...println(“deu beleza?”);
}
}
int x = getNumPositivoMenorQueDez();
switch (x) {
case 2:
case 4:
case 6:
case 8:
...println(“é par”); break;
default:
...println(“é ímpar”); break;
} // passagem completa
imprime o que?short s = 12;
// --s;
switch (s) {
case 11: ...print(“11”);
default: ...print(“default”);
case 13: ...print(“13”);
}
switch-case-defaultshort s = 12;
// --s;
switch (s) {
case 11: ...print(“11”);
default: ...print(“default”);
case 13: ...print(“13”);
}
� imprime “default13”
� descomentando a segunda linha do exemplo anterior, seria
impresso “11default13”
� Ou seja, a instrução default pode não vir no final da instrução
switch e funciona como qualquer instrução case na passagem
completa
while e do-while� while útil quando não se sabe quantas vezes o bloco terá que
ser repetido
while (expressaoBooleana) {
// um mói de coisa
}
� do-while útil quando se quer executar um bloco ao menos
uma vez antes de avaliar a expressão
do {
// outro mói
} while (outraExpressao); // <- detalhe no ponto-e-vírgula
for� útil quando se souber o números de vezes que executará as
instruções do bloco do loop
for (/* inicialização */ ; /* condição */ ; /* iteração */) {
// corpo do loop
}
for (int k = 0, j = 1; k < 10 && j < 10; k++, --j) {}
// beleza
}
...println(k); // k já não existe mais aqui
...println(j); // cannot find symbol
� ecxeto por uma saída forçada, as expressões de iteração e
condição serão as últimas a seres executada num loop for
saídas forçadas e +�break salto para a 1ª instrução depois do loop
�return retornará imediatamente ao método chamador
�System.exit() o programa será interrompido, VM será
encerrada
int i = 0;
for(;i<10;) {
++i;
// mais coisas aqui
} // equivalente a um while
for (;;) { ... } // loop infinito
for (; false; ) { ... } // unreachable statement
for (int a = 1, b = 3; b != 1; System.out.println(b)) { // válido!
b -= a;
}
for aprimorado (for-each)for (declaração : expressão)
int x;
long x2;
Long[] La = {4L, 5l, 6l};
long[] la = {7l, 8L, 9};int[][] dobrado = {{3, 2, 1}, {6, 5, 4}};
String[] ss = {“um”, “dois”, “quatro”};
Animal[] animais = {new Dog(), new
Cat()};
for (float y: la); // ??
for (long lp: La);
for (int[] n: dobrado);
for (int n2: dobrado[1]);
for (String s: ss);
for (Object o: ss);
for(Animal a: animais);
for(x2: la);
for(int x2: dobrado);
for(int x3: la);
for(Dog d: animais);
continue e break�continue próxima iteração do laço (não pode vir fora um loop)
�break vai para próxima linha depois do laço
for (int in = 0; i < 10; i++) {
continue; // loop infinito?
}
for (int i = 0; i < 10; i++) {
if (i & 1 == 0) {
continue;
}
if (i == 8) {
break;
}
...println(i);
}
instruções rotuladas� muitas instruções em java podem ser rotuladas, mas isso é
mais comum em loops
� úteis em loops aninhados
� o rótulo precisa estar de acordo com as regras de nomes de
variáveis válidos
rotulo1:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
...println(j);
continue rotulo1;
}
...println(“ufa”);
}
...println(“fim”);
+ rótulos� as instruções continue e break rotuladas devem ficar dentro
do loop que tiver o mesmo rótulo ou o código não será
compilado
int b = 10;
int[] a = new int[4];
1rotulo:
for (int n: a) break 1rotulo;
rotulo2: {
while (b > 0) {
...println(b--);
}
continue rotulo2;
}
manipulação de exceções� produz código eficiente e organizado
� mantém código de exceções separado do código “principal'
� permite “reutilização” do código de exceção para as diferentes
exceções possíveis
� exceção significa “condição excepcional” (falha no hardware,
exaustão de recursos, erros...)
� quando um evento excepcional ocorre, diz-se que uma
exceção será lançada
� o código responsável por fazer algo com a exceção é
chamado de manipulador de exceções
try catch� try indica um bloco de código em que poderá ocorrer uma
exceção (região protegida)
� a cláusula catch associa uma (ou mais) exceção(ões) a um
bloco de código que a manipulará
� se existirem blocos catch, então eles devem ficar sempre
depois do bloco try e nada pode ficar entre eles
try {
captureArquivoNaRede();
leiaArquivoePreenchaTabela();
}
catch (NaoPodeCapturarArquivoNaRede e) {
useArquivoLocal();
}
finally� o bloco finally será sempre executado, mesmo que nenhuma
exceção seja lançada
� útil para “executar limpeza “ (fechar arquivos, liberar sockets
de rede, etc)
void fazAlgo() {
try {
int a = 10;
a /= 0;
} catch (ArithmeticException e) {
System.out.println("no catch");
return;
} finally {
System.out.println("no finally");
}
} // o que será impresso?
try {
int a = 10 / 0;
}
System.out.println(a);
try {
int b = 10 / 0;
} finally {
...println(“finally”);
} catch (Exception e) {
...println(“catch”);
}System.out.println(b);
propagação de exceçõesclass Pilha {
public static void main(String[] args) {
new Cap5().facaUm();
}
void facaUm() {
facaDois();
}
void facaDois() {
int a = 1/0;
}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Cap5.facaDois(Cap5.java:11)
at Cap5.facaUm(Cap5.java:8)
at Cap5.main(Cap5.java:5)
fazDois()
fazUm()
main()
hierarquia de exceções� as exceções são sempre subclasses de java.lang.Exception
� há duas subclasses que derivam de Throwable: Exception e Error
� os aplicativos geralmente não conseguem se recuperar de um erro,
então mesmo que seu código não os manipule, ele ainda será compilado
� a classe Throwable fornece o método printStackTrace() para exibir o
rastreamento de pilha do local onde a exceção ocorreu
� os tipos RunTimeException, Exception, Error e Throwable podem ser
lançados com o uso da palavra throw e podem ser capturados (embora
raramente seja capturado algo que não seja um subtipo de Exception)
Error
Object Throwable
Exception RunTimeException
correspondência de exceções� os manipuladores de exceções mais específicos devem
sempre ser inseridos acima dos de exceções gerais
� se uma classe Exception não for o subtipo ou supertipo da
outra, a ordem na qual as cláusulas catch serão inseridas não
importará
try {
RandomAccessFile raf = new RandomAccessFile("myfile.txt", "r");
byte[] b = new byte[1000];
raf.readFully(b, 0, 1000);
} catch (FileNotFoundException e) {
System.out.println("file not found");
} catch (IOException e) {
System.out.println("IO Error");}
declarando exceções� uma exceção é dita “verificada” se não é do tipo
RunTimeException
� as exceções verificadas que um método pode lançar devem
ser declaradas, mesmo que ele lance de maneira indireta
� utiliza-se a palavra-chave throws na assinatura do método
para declarar que o método lança uma dada exceção
� quando um método declara que lança uma exceção, não
significa que ele sempre o fará, mas sim que ele pode fazê-lo
void doStuff() { doMore(); }
void doMore() {
throw new IOException();
} // dois erros aqui
+ exceçõespublic static void main(String[] args) {
try {
new Cap5().fazUm();
} catch (IOException e) {}
// IOException is never thrown in body
// of corresponding try statement
}
void fazUm() { fazDois(); }
void fazDois() {
try {
throw new IOException();
} catch (IOException rte) {
rte.printStackTrace();
}
}
ainda + exceçõespublic static void main(String[] args) {
new Cap5().fazUm();
}
void fazUm() {
try {
throw new Error();
} catch (Error e) {
throw e;
}
} void fazUm() {
try {
throw new IOException();
} catch (IOException e) {
throw e;
}
exceções e erros lançados pelo
JVM� NullPointerException
class NPE {
static String s;
public static void main(String[] args) {
System.out.println(s.length());
}
}
� StackOverflowError
void recursivo() {
recursivo()
}
exceções & erros lançados
programaticamente� “programaticamente” = criado por um aplicativo e/ou por um
desenvolvedor de API
// uma possível implementação do parseInt() de Integer:
int parseInt(String s) throws NumberFormatException {
boolean parseSuccess = false;
int resulta = 0;
// parsing complicado aqui
if (!parseSuccess) {
throw new NumberFormatException();
}
return result;
}
� AssertionError também é lançado programaticamente
Os dez erros e exceções principais� ArrayIndexOfBoundsException: lançada ao se tentar acessar um
array com um valor de índice inválido
int[] a = new int[10];
a[a.length] = 0;
� ClassCastException: lançada ao se tentar converter uma
variável de referência em um tipo que não passa no teste é-um
Object o = new Integer(0);
System.out.println((String)o);
� IllegalArgumentException: lançada quando um método
recebe um argumento formatado de forma diferente do que o
método espera
- lançado programaticamente
Os dez erros e exceções principais� IllegalStateException: quando o estado do ambiente não bate com a
operação sendo tentada, p.ex., usando-se um Scanner que já foi fechado.
- lançada programaticamente
� NullPointerException
- lançada pela JVM
� NumberFormatException: lançada quando um método que
converte uma String em um número recebe uma String que não
consegue converter.
- lançada programaticamente
String s = "123deoliveira4";
int i = Integer.parseInt(s);
� AssertionError: daqui a pouco
- lançada programaticamente
Os dez erros e exceções principais� ExceptionInInitializerError: ao se tentar inicializar uma variável
estática de um bloco de inicialização.
- lançada pelo JVM
class Cap5 {
static int a;
static {a = 2/0;}
}
� StackOverflowError
- lançada pelo JVM
� NoClassDefFoundError: quando o JVM não consegue
encontrar uma classe de que precisa, por causa de um erro de
linha de comando, uma questão referente ao classpath ou um
arquivo .class que esteja faltando.
$java ClasseX.class
assertivas� pertime que se teste suas suposições durante o desenvolvimento, sem
o desgaste (de tempo e sobrecarga do programa) de escrever
manipuladores para exceções que se supõe que nunca ocorrerão
void tam(int num) {
assert (num >= 0);
// código útil aqui
}
// ao invés de
void tam(int num) {
if (num >= 0) {// código útil aqui
}
else {
...println(“o número é negativo”);
}
}
duas versões de assert� Muito simples: assert (y > x);
� Simples: assert (num >= 0): "tá com mopa"
Exception in thread "main" java.lang.AssertionError: tá com mopa
at Cap5.tam(Cap5.java:11)
at Cap5.fazAlgo(Cap5.java:8)
at Cap5.main(Cap5.java:5)
� normalmente as assertivas são ativadas quando um aplicativo está
sendo testado e deuprado, porém, são desativadas quando ele é
distribuido
� quando a palavra “expressão” for citada em alguma questão, suponha
que ela está se referindo à primeira expressão de um assert (a expressão
booleana)
regras das expressões de assertivasvoid semRetorno() {}
int retornaInt() { return 0; }
void vai() {
int x = 1;
boolean b = true;
assert(x==1);
assert(x = 1);
assert(b);
assert(x);
assert true;
assert 0;
assert(x == 1): x;assert(x == 1): ;
assert(x ==1): retornaInt();
assert(x == 1): semRetorno();
assert(x == 1): new ValidAssert();
assert(x == 1): ClasseB b;
}
ativando assertivas� as assertivas foram adicionadas na versão 1.4 e “assert” se tornou
uma palavra-chave, logo você deve utilizar “assert” como identificador ou
como palavra-chave, mas não ambos
� o compilador Java 5 usará a palavra-chave assert por padrão, a não
ser você o instrua do contrário
char assert = 'a';
$ javac Cap5.java // Error
$ javac -source 1.3 Cap5.java // Warning
assert(a > 0);
$ javac -source 5 Cap5.java // Beleza
$ javac -source 1.3 Cap5.java // Error
execução de assertivas� as assertivas vêm desativadas por padrão
� ativando assertivas:
$ java -ea pacote.subpacote.Classe
$ java -enableassertions pacote.subpacote.Classe
� desativando assertivas
$ java -da pacote.subpacote.Classe
$ java -disableassertions pacote.subpacote.Classe
� ativação e desativação seletiva:
$ java -ea:com.foo.Bar$ java -ea:com.foo...
$ java -ea -dsa � desativando nas classes do sistema
$ java -ea -da:com.foo...
uso apropriado� “apropriado” = “correto”
� nunca se deve manipular uma falha de assertiva (apesar de ser
possível)
� o erro AssertionError não concede acesso ao objeto que o gerou (??)try {
assert (num >= 0): "deu mopa";
} catch (AssertionError ae) {
ae.printStackTrace();
} // uso inapropriado
� não use assertivas para validar argumentos de um método public: é
preciso garantir que nenhuma restrição a argumentos seja imposta
public void facaAlgo(int x) {
assert (x > 0);
// código que mexe com x
} // melhor seria lançar uma IllegalArgumentException
+ uso apropriado� use assertivas para validar argumentos de um método privado (pois
provavelmente você controlará todos os métodos que o chamarão)
private fazAlgo(byte x) {
assert(x > 0);
}
� não use assertivas para validar argumentos de linha de comando (se
precisar fazer isso, use o mecanismo de exceções)
� use assertivas, mesmo em métodos públic, para procurar instruções
case que sabe que nunca ocorrerãoswitch(x) {
case 1: fazUm();
case 2: fazDois();
case 3: fazTres();
default: assert false;
}
++ uso apropriado� não use assertivas que posdem causar efeitos colaterais
public void fazAlgo() {
assert(modificaAlgo());
// continua...
}
boolean modificaAlgo() {
x++ = y; // outro erro aqui
return true;
}
� uma assertiva deve deixar o programa no mesmo estado em que estava antes da expressão, pois não há garantia de que as expressões
assertivas sejam sempre executadas
fim