Java if, else if, else
Até agora, os seus programas rodavam todas as linhas, de cima para baixo, sempre. Com o if, o programa passa a escolher: roda um trecho só quando uma condição é verdadeira, e outro trecho quando não é. É aqui que o programa começa a "pensar".
- Como o
if("se") roda um bloco só quando a condição étrue. - Como o
else("senão") dá um caminho alternativo. - Como o
else ifescolhe entre várias opções, e por que a ordem importa. - O que são blocos e chaves, e o perigo real de omitir as chaves (e de um
;a mais). - Como colocar um
ifdentro de outro e comparar Strings noif. - Os erros reais:
'else' without 'if',=no lugar de==, variável que "sumiu" depois do bloco.
A ideia: uma bifurcação no caminho
Pense num GPS: "se a rua estiver bloqueada, vire à direita; senão, siga em frente". O programa é o carro, andando linha por linha. O if é a bifurcação: o caminho escolhido depende da resposta a uma pergunta de sim ou não, uma expressão booleana.
if: fazer algo só se…
public class Main {
public static void main(String[] args) {
double nota = 8.5;
if (nota >= 7.0) {
System.out.println("Aprovada!");
}
System.out.println("Fim do programa");
}
}
$ java Main.java Aprovada! Fim do programa
- if
- Palavra reservada: "se". Sempre minúscula.
- (nota >= 7.0)
- A condição, sempre entre parênteses. Tem de ser uma expressão booleana: algo que dá
trueoufalse. - { … }
- O bloco: as linhas entre as chaves rodam só se a condição for
true. Se forfalse, o Java pula o bloco inteiro. - System.out.println("Fim do programa");
- Está fora do bloco, depois do
}: roda sempre, seja qual for a nota.
Com nota = 5.5, a saída seria só Fim do programa: a condição dá false e o println("Aprovada!") é pulado. Repare na indentação (os 4 espaços a mais dentro do bloco): o Java não precisa dela, mas é ela que mostra a quem lê o que está dentro do if.
else: senão, faça outra coisa
O else ("senão") vem logo depois do bloco do if e tem o seu próprio bloco, que roda quando a condição é false. Sempre roda exatamente um dos dois blocos, nunca os dois, nunca nenhum.
public class Main {
public static void main(String[] args) {
double nota = 5.5;
if (nota >= 7.0) {
System.out.println("Aprovada!");
System.out.println("Parabéns, Ana.");
} else {
System.out.println("Reprovada.");
System.out.println("Faltaram " + (7.0 - nota) + " pontos.");
}
System.out.println("Fim do programa");
}
}
$ java Main.java Reprovada. Faltaram 1.5 pontos. Fim do programa
Um bloco pode ter quantas linhas quiser. Como 5.5 não é >= 7.0, o Java pulou o primeiro bloco e rodou o do else. O else não tem condição: ele é simplesmente "todos os outros casos".
else if: várias opções
Para escolher entre mais de dois caminhos, encadeie else if ("senão, se"). O Java testa as condições de cima para baixo e roda o bloco da primeira que for verdadeira; as de baixo nem são testadas. O else final, opcional, pega o que sobrou.
public class Main {
public static void main(String[] args) {
double nota = 7.8;
if (nota >= 9.0) {
System.out.println("Conceito A");
} else if (nota >= 7.0) {
System.out.println("Conceito B");
} else if (nota >= 5.0) {
System.out.println("Conceito C");
} else {
System.out.println("Conceito D");
}
}
}
$ java Main.java Conceito B
| Passo | Pergunta | Resposta (nota 7.8) | O que acontece |
|---|---|---|---|
| 1 | nota >= 9.0? | false | Pula o bloco, vai para o próximo teste |
| 2 | nota >= 7.0? | true | Mostra Conceito B e sai da escada inteira |
| 3 | nota >= 5.0? | (não é testada) | |
| 4 | else | (não roda) |
Repare que o teste 2 não precisa dizer nota >= 7.0 && nota < 9.0: se chegou ali, é porque o teste 1 já deu false, ou seja, a nota é menor que 9.
A ordem importa
Como vale a primeira condição verdadeira, uma escada na ordem errada dá resultados errados, sem nenhum aviso:
public class Main {
public static void main(String[] args) {
double nota = 9.5;
if (nota >= 5.0) {
System.out.println("Conceito C");
} else if (nota >= 7.0) {
System.out.println("Conceito B");
} else if (nota >= 9.0) {
System.out.println("Conceito A");
}
}
}
$ java Main.java Conceito C « 9.5 merecia A!
9.5 é >= 5.0, então o primeiro teste "pegou" a nota, e os outros nunca foram testados. Com condições do tipo "maior ou igual", comece pela mais exigente (a maior). Na dúvida, pergunte: "um valor que chega até aqui pode cair num teste acima por engano?".
Missão: complete a escada de else if para classificar a temperatura: 30 ou mais, Muito quente; 25 ou mais, Calor; 15 ou mais, Agradável; abaixo disso, Frio. Com 28 graus, a saída deve ser Calor. Teste também com 31, 15 e 10.
public class Main {
public static void main(String[] args) {
int temperatura = 28;
if (temperatura >= 30) {
System.out.println("Muito quente");
}
}
}
public class Main {
public static void main(String[] args) {
int temperatura = 28;
if (temperatura >= 30) {
System.out.println("Muito quente");
} else if (temperatura >= 25) {
System.out.println("Calor");
} else if (temperatura >= 15) {
System.out.println("Agradável");
} else {
System.out.println("Frio");
}
}
}
Blocos e chaves: não economize
Se o bloco tem uma única linha, o Java permite omitir as chaves: if (x > 0) System.out.println("positivo");. Parece prático, mas é uma armadilha. Sem chaves, o if controla só a próxima instrução, não importa como as linhas estão alinhadas. Veja o que acontece quando alguém acrescenta uma linha depois:
Este código tem um erro de propósito (de lógica: ele compila).
public class Main {
public static void main(String[] args) {
int saldo = 50;
if (saldo < 0)
System.out.println("Saldo negativo!");
System.out.println("Cobrando juros...");
System.out.println("Saldo: " + saldo);
}
}
$ java Main.java Cobrando juros... « o saldo é positivo e mesmo assim cobrou juros! Saldo: 50
A indentação engana: parece que as duas linhas estão "dentro" do if. Para o Java, só a primeira está. A segunda é uma linha comum, que roda sempre. O javac não avisa nada. Com chaves, não há dúvida:
if (saldo < 0) {
System.out.println("Saldo negativo!");
System.out.println("Cobrando juros...");
}
Mesmo com uma linha só. É a recomendação dos guias de estilo de Java (e a causa de falhas de segurança famosas em programas reais). As IDEs colocam as chaves para você.
O ; que esvazia o if
Um ponto e vírgula logo depois dos parênteses é outro erro silencioso. Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
int saldo = 50;
if (saldo < 0); {
System.out.println("Saldo negativo!");
}
System.out.println("Saldo: " + saldo);
}
}
$ java Main.java Saldo negativo! « com saldo 50?! Saldo: 50
O ; é uma instrução vazia ("não faça nada"), e é ela que o if controla. O bloco { … } que vem depois fica solto e roda sempre. O javac compila normalmente, mas, se você pedir todos os avisos com -Xlint:all, ele aponta o problema:
$ javac -Xlint:all Main.java
Main.java:4: warning: [empty] empty statement after if
if (saldo < 0); {
^
1 warning
empty statement after if = "instrução vazia depois do if". Um warning (aviso) não impede a compilação, mas quase sempre indica um erro. As IDEs mostram esse aviso automaticamente.
Missão: rode e veja os juros cobrados de um saldo positivo. Coloque as chaves que faltam para que as duas mensagens fiquem dentro do if. A saída correta é só Saldo: 50.
public class Main {
public static void main(String[] args) {
int saldo = 50;
if (saldo < 0)
System.out.println("Saldo negativo!");
System.out.println("Cobrando juros...");
System.out.println("Saldo: " + saldo);
}
}
public class Main {
public static void main(String[] args) {
int saldo = 50;
if (saldo < 0) {
System.out.println("Saldo negativo!");
System.out.println("Cobrando juros...");
}
System.out.println("Saldo: " + saldo);
}
}
Variáveis criadas dentro do bloco
Uma variável declarada dentro de um bloco só existe ali dentro; ao chegar no }, ela some. Esse "alcance" se chama escopo (aula própria em Escopo). Se você precisa do valor depois do if, declare a variável antes e só atribua dentro:
public class Main {
public static void main(String[] args) {
double nota = 8.0;
String situacao;
if (nota >= 7.0) {
situacao = "aprovada";
} else {
situacao = "reprovada";
}
System.out.println("Situação: " + situacao);
}
}
$ java Main.java Situação: aprovada
Com if e else, o javac sabe que situacao sempre recebe um valor. Sem o else, ele reclama (veja "Quando dá errado"). Para casos simples como este, o operador ternário faz o mesmo em uma linha.
if dentro de if
Um bloco pode conter qualquer código, inclusive outro if. Isso se chama if aninhado (como ninhos, um dentro do outro). Use quando a segunda pergunta só faz sentido depois da primeira:
public class Main {
public static void main(String[] args) {
int idade = 20;
boolean temIngresso = true;
if (idade >= 18) {
if (temIngresso) {
System.out.println("Pode entrar no show.");
} else {
System.out.println("Compre um ingresso na bilheteria.");
}
} else {
System.out.println("Show proibido para menores.");
}
}
}
$ java Main.java Pode entrar no show.
Cada else pertence ao if cujo bloco acabou de fechar: o primeiro else responde a if (temIngresso); o segundo, a if (idade >= 18). A indentação mostra isso a olho nu. Evite mais de dois ou três níveis: quando os ninhos ficam fundos, uma condição combinada com && ou uma escada de else if costuma ficar mais clara.
Comparar Strings no if
A regra da aula Strings vale em dobro aqui: no if, compare textos com equals. O == compila e às vezes funciona, o que torna o erro traiçoeiro:
public class Main {
public static void main(String[] args) {
String digitado = "SIM";
String resposta = digitado.toLowerCase();
System.out.println(resposta);
if (resposta == "sim") {
System.out.println("== disse: confirmado");
} else {
System.out.println("== disse: NÃO confirmado");
}
if (resposta.equals("sim")) {
System.out.println("equals disse: confirmado");
}
if (digitado.equalsIgnoreCase("sim")) {
System.out.println("equalsIgnoreCase disse: confirmado");
}
}
}
$ java Main.java sim « o texto é exatamente "sim"… == disse: NÃO confirmado « …mas o == diz que não equals disse: confirmado equalsIgnoreCase disse: confirmado « aceita SIM, Sim, sim…
toLowerCase() criou uma String nova durante a execução, e o == compara se são o mesmo objeto, não o mesmo texto. Com dados que vêm do teclado (Scanner), isso acontece sempre.
Formas de decidir: qual usar?
| Situação | Use |
|---|---|
| Fazer algo só em um caso | if |
| Dois caminhos (sim / não) | if … else |
| Várias faixas ou condições diferentes | if … else if … else |
| Escolher entre dois valores para guardar ou mostrar | Operador ternário cond ? a : b |
| Comparar uma variável com vários valores exatos (1, 2, 3; "A", "B") | switch ou switch com setas |
| Uma pergunta que só faz sentido depois de outra | if aninhado |
Quando dá errado
error: 'else' without 'if'
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
int idade = 20;
if (idade >= 18);
System.out.println("Maior de idade");
else
System.out.println("Menor de idade");
}
}
$ javac Main.java
Main.java:6: error: 'else' without 'if'
else
^
1 error
O que aconteceu: "else sem if". O ; depois do if encerrou o if ali mesmo. O println virou uma linha comum, e o else ficou órfão: só pode vir imediatamente depois do bloco (ou da instrução) de um if. O mesmo erro aparece quando, sem chaves, há duas linhas entre o if e o else, ou quando uma chave } está fora do lugar.
Como resolver: tire o ; e use chaves: if (idade >= 18) { … } else { … }.
error: incompatible types: int cannot be converted to boolean (= no lugar de ==)
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
int idade = 20;
if (idade = 18) {
System.out.println("Fez 18 anos!");
}
}
}
$ javac Main.java
Main.java:4: error: incompatible types: int cannot be converted to boolean
if (idade = 18) {
^
1 error
O que aconteceu: um = só é atribuição ("guarde 18 em idade"), e o resultado dela é o número 18. O if precisa de um boolean e recebeu um int. Em C, isso compilaria e daria um erro difícil de achar; o Java, por exigir boolean, pega o engano.
Como resolver: para comparar, dois sinais: if (idade == 18).
= com boolean não dá erro (e sempre entra no if)
Este código tem um erro de propósito (de lógica: ele compila).
public class Main {
public static void main(String[] args) {
boolean ligado = false;
if (ligado = true) {
System.out.println("Está ligado");
}
}
}
$ java Main.java Está ligado
O que aconteceu: aqui o tipo bate: ligado = true guarda true e o resultado é true, um boolean. O if sempre entra, e ainda estragou o valor de ligado.
Como resolver: nem = nem ==: escreva if (ligado) (veja Expressões Booleanas).
error: '(' expected
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
int idade = 20;
if idade >= 18 {
System.out.println("Maior de idade");
}
}
}
$ javac Main.java
Main.java:4: error: '(' expected
if idade >= 18 {
^
Main.java:4: error: ')' expected
if idade >= 18 {
^
2 errors
O que aconteceu: em Java, os parênteses da condição são obrigatórios (em Python e Go, não).
Como resolver: if (idade >= 18) {.
error: cannot find symbol … symbol: variable situacao
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
double nota = 8.0;
if (nota >= 7.0) {
String situacao = "aprovada";
} else {
String situacao = "reprovada";
}
System.out.println(situacao);
}
}
$ javac Main.java
Main.java:9: error: cannot find symbol
System.out.println(situacao);
^
symbol: variable situacao
location: class Main
1 error
O que aconteceu: as duas variáveis situacao foram criadas dentro dos blocos e deixaram de existir no }. Na linha 9, não há nenhuma situacao visível.
Como resolver: declare antes do if (String situacao;) e só atribua dentro dos blocos, como no exemplo da seção "Variáveis criadas dentro do bloco".
error: variable situacao might not have been initialized
Este código tem um erro de propósito.
public class Main {
public static void main(String[] args) {
double nota = 8.0;
String situacao;
if (nota >= 7.0) {
situacao = "aprovada";
}
System.out.println(situacao);
}
}
$ javac Main.java
Main.java:8: error: variable situacao might not have been initialized
System.out.println(situacao);
^
1 error
O que aconteceu: "a variável pode não ter sido inicializada". Se a nota fosse menor que 7, ninguém daria valor a situacao. O javac analisa todos os caminhos possíveis e não deixa usar uma variável que, em algum caminho, ficou sem valor (mesmo que, com 8.0, o caminho seja outro).
Como resolver: acrescente o else que atribui o outro valor, ou dê um valor inicial na declaração.
error: class, interface, annotation type, enum, record, method or field expected
$ javac Main.java Main.java:10: error: class, interface, annotation type, enum, record, method or field expected } ^ 1 error
O que aconteceu: sobrou uma chave }. Ao fechar blocos de if dentro de if, é fácil perder a conta: o javac chegou a uma } depois do fim da classe e esperava outra coisa ali. Quando falta uma chave, o erro costuma ser reached end of file while parsing.
Como resolver: confira os pares de chaves pela indentação; as IDEs destacam o par de cada chave.
Referência
| Forma | Roda |
|---|---|
if (cond) { A } | A, se cond for true |
if (cond) { A } else { B } | A ou B, nunca os dois |
if (c1) { A } else if (c2) { B } else { C } | O bloco da primeira condição verdadeira; C se nenhuma |
if (c1) { if (c2) { A } } | A, se c1 e c2 forem true (o mesmo que if (c1 && c2)) |
if (texto.equals("x")) | Comparação de String (nunca ==) |
if (ativo) / if (!ativo) | Variável boolean, sem == true |
Exercícios
Missão final: calcule o frete de uma loja. Compras de 200 ou mais: Frete grátis. Senão, se o estado for "PE": Frete: R$ 10. Senão: Frete: R$ 25. Com a compra de 150 em PE, a saída deve ser Frete: R$ 10. Use equals para o estado.
public class Main {
public static void main(String[] args) {
double compra = 150.0;
String estado = "PE";
// escreva o if / else if / else
}
}
public class Main {
public static void main(String[] args) {
double compra = 150.0;
String estado = "PE";
if (compra >= 200) {
System.out.println("Frete grátis");
} else if (estado.equals("PE")) {
System.out.println("Frete: R$ 10");
} else {
System.out.println("Frete: R$ 25");
}
}
}
1. A palavra que falta
Complete para mostrar "Ímpar" quando o número não for par:
2. Comparar texto
Complete a condição para testar se cor é "azul":
3. Qual a saída?
Com int x = 10;, o que mostra if (x > 5) { System.out.println("A"); } else if (x > 8) { System.out.println("B"); } else { System.out.println("C"); }?
4. Com int x = -3;, o que este código mostra?
if (x > 0)
System.out.println("positivo");
System.out.println("fim");
5. Por que if (idade = 18) não compila, com int idade?
6. Numa escada de else if, quantos blocos rodam no máximo?
Resumo
if (condição) { … }roda o bloco só quando a condição étrue; a condição vai entre parênteses e tem de serboolean.elseé o "senão": exatamente um dos dois blocos roda.else ifencadeia opções; vale a primeira verdadeira, então a ordem importa (comece pela mais exigente).- Use sempre chaves. Sem elas, o
ifcontrola só a próxima linha, e a indentação mente. Nada de;depois do). - Variável criada dentro do bloco some no
}: declare antes se precisar dela depois. - Strings no
if:equals. Comparação:==, nunca=.