Comentários
Utilização de estruturas básicas, mas que são de extrema importância, pois rompem o fluxo linear do código tornando-o mais dinâmico.
Fonte: Shuttersock.
Deseja ouvir este material?
Áudio disponível no material digital.
Caro estudante, bem-vindo à segunda seção da segunda unidade de estudos sobre Linguagem Orientada a Objetos.
Comecemos com uma questão: qual desenvolvedor nunca utilizou, em seus códigos, estruturas de decisão, de repetição, operadores aritméticos, relacionais e lógicos? A maioria dos desenvolvedores, se não todos, já utilizou, mas qual a melhor estrutura de tomada de decisão a ser utilizada? Qual a melhor estrutura de repetição a ser utilizada? Nesta seção, você terá a oportunidade de aprender a sintaxe básica por trás dos comandos if, if-else, operador ternário, switch, for, while e do-while, bem como conhecerá todos os tipos primitivos de dados presentes no Java.
Como forma de contextualizar sua aprendizagem, lembre-se de que você é contratado de uma startup e que seu chefe quer apresentar um simulador completo de robô em Java capaz de transportar caixas em uma sala. Ele está muito satisfeito com o que você está desenvolvendo, mas sabe que ainda há muito trabalho a se fazer. Assim, ele lhe pediu a criação de uma classe que modele a sala em que o robô irá operar e uma classe que modele a entidade caixa. Percebendo que o robô que você modelou não possui nenhum atributo que defina a sua orientação, solicitou, também, um atributo em que a orientação do robô seja especificada e que a manipulação desse atributo utilize alguma estrutura de decisão. A fim de testar a aplicação, ele lhe pediu um robô que se deslocasse em forma de um quadrado, utilizando laços de repetição, mas percebeu que o projeto do simulador do robô estava apenas na sua máquina e lhe pediu para que começasse a utilizar o GitHub, mantendo o código sempre seguro e versionado.
Diante do desafio que lhe foi apresentado, como você irá criar essa sala que representa o mundo do seu robô? Como você irá criar as caixas que comporão o cenário? Como você irá criar esse atributo orientação? Qual estrutura de decisão você irá utilizar para definir a orientação. Como você irá trabalhar com essas diversas classes e como você irá conectá-las? Esta seção irá ajudá-lo a ter um maior domínio das tarefas requisitadas pelo seu chefe, e agora que você foi apresentado à sua nova situação-problema, estude esta seção e compreenda algumas das estruturas básicas da linguagem Java. Essas estruturas, apesar de básicas, são de extrema importância para a construção de qualquer aplicação de pequeno e grande porte.
E aí, vamos juntos compreender esses conceitos e resolver esse desafio?
Bom estudo!
A linguagem Java, assim como a maioria das linguagens de programação, possui estruturas de controle, como tomadas de decisão e laços de repetição. Outro aspecto inerente à maioria das linguagens de programação diz respeito aos operadores aritméticos, relacionais e lógicos. A linguagem Java é fortemente tipada, ou seja, os tipos das variáveis são importantes para a manipulação de dados e devem ser declarados no início de criação da variável. Mas calma, todos esses aspectos mencionados serão abordados com mais detalhes nesta seção.
Antes de darmos continuidade, gostaríamos de ressaltar dois pontos importantes:
Antes de explicarmos a estrutura de decisão, é bom lembrarmos que a linguagem Java, assim como a maioria das linguagens de programação, executa o seu código de forma sequencial e de cima para baixo, linha a linha. Às vezes, é necessário romper com essa execução sequencial, e queremos executar um trecho do código somente se alguma coisa ocorrer. Essas tomadas de decisão rompem com o fluxo linear do código, criando bifurcações que ajudam a tornar o código mais dinâmico.
A principal estrutura de decisão é o comando if e if-else. Esses comandos também podem ser concatenados sucessivamente por outros ifs, como em if-elseif-else, etc. A Figura 2.3 mostra, de forma gráfica, como ocorre o fluxo de execução em cada um desses comandos mencionados.
Na Figura 2.3, podemos perceber que esses três comandos rompem com o fluxo sequencial do código se uma determinada condição (D1 ou D2) for satisfeita. Assim, se o valor de D1 for verdadeiro, o comando C1 será executado; se o valor de D1 for falso, um outro comando será executado. Ainda, na Figura 2.3, C1, C2, C3 e C4 indicam comandos a serem executados, já D1 e D2 indicam tomadas de decisão a serem avaliadas.
As estruturas dos comandos de decisão em nível de código podem ser sintetizadas conforme o Quadro 2.2 a seguir.
Comando: if |
Comando: if-else |
Comando: if-elseif-else |
---|---|---|
if (ExpLógicaA) { |
if (ExpLógicaA) { |
|
Podemos perceber que a sintaxe é a mesma da linguagem de programação C. Vamos analisar por partes esse comando. Inicialmente, na primeira coluna do Quadro 2.2, temos a palavra reservada if, logo, em seguida, devemos colocar uma expressão que possua um valor lógico (verdadeiro ou falso) dentro de parênteses. Após isso, a abertura do bloco de código utilizando-se as chaves é necessária se a quantidade de comandos a seguir for maior que um. No Quadro 2.2, a sequência SeqDeComandosA só será executada se a expressão ExpLógicaA for verdadeira. Por sua vez, na segunda coluna, o comando SeqDeComandosB só será executado se a expressão ExpLógicaA for falsa. Ainda no Quadro 2.2, na terceira coluna, temos um exemplo de como é feita a concatenação de dois comandos if.
Uma forma mais simplificada de se construir comandos do tipo if-else dá-se por meio do operador ternário em Java. O nome operador ternário deve-se ao fato de que o comando é quebrado em três partes separadas pelos símbolos de interrogação (?) e de dois pontos (:). A utilização desse operador é igual ao comando da linguagem C. Considere o seguinte trecho de código em Java no Quadro 2.3, em que foi utilizado, na esquerda, if-else e, na direita, o operador ternário.
Comando: if-else |
Comando: operador-ternário |
---|---|
|
ExpLógicaA ? ComandoA : ComandoB; |
No Quadro 2.3, os dois códigos são equivalentes. No operador ternário, inicialmente, temos uma expressão lógica que será avaliada (ExpLógicaA), caso ela seja verdadeira, o ComandoA será executado, caso ela seja falsa, o ComandoB será executado. Uma forma muito simples e útil de utilização do operador ternário se dá para o cálculo do máximo e mínimo de dois valores. Analise o Quadro 2.4 a seguir.
exemplo máximo |
exemplo mínimo |
---|---|
|
|
No exemplo acima, a variável max irá armazenar o valor máximo entre as variáveis x e y (considere que x e y foram declarados anteriormente), pois, caso o x seja maior que y, então, x será retornado, caso o x não seja maior que y, então, y será retornado. O exemplo ao lado calcula o mínimo e seu funcionamento é semelhante. Implemente o código completo para calcular o máximo e o mínimo e analise o resultado.
O operador ternário pode também ser combinado com ele mesmo, criando expressões ainda mais complexas, como nos trechos de códigos mostrados a seguir:
O operador ternário pode também ser combinado com ele mesmo, criando expressões ainda mais complexas, como nos trechos de códigos mostrados a seguir:
String compXY = x>y ? "maior" : x<y ? "menor" :"igual";
String diaSem = dia==0 ? "dom" : dia==1 ? "seg" :
dia==2 ? "ter" : dia==3 ? "qua" :
dia==4 ? "qui" : dia==5 ? "sex" :"sab";
Fonte: elaborado pelo autor.Acima, no primeiro exemplo, temos a comparação entre duas variáveis: x e y. Se x for maior que y, retornará “maior”, se x for menor que y, retornará “menor”, se forem iguais, retornarão “iguais”.
No segundo exemplo mostrado acima, temos a comparação entre a variável dia com os números inteiros de 0 a 5. Caso o dia seja 0, então, retornará o valor “dom”, indicando domingo; caso o dia seja 1, então, retornará o valor "seg", representando segunda-feira; e esse raciocínio se repetirá até a sexta-feira, e caso o dia não seja nenhum dos anteriores, então, o valor "sab", indicando o sábado, será retornado.
Caro aluno, acesse o conteúdo no Java Tutor Comparação XY e no Java Tutor DiaDaSemana, presentes no tópico Referências, e execute o código acompanhando a sua execução, linha a linha, para entendê-lo melhor.
Outra estrutura de decisão é o comando switch. Esse comando provê o que chamamos de estrutura de seleção múltipla baseada em alguma variável de controle. A Figura 2.4 mostra, de forma gráfica, como ocorre o fluxo de execução no comando switch-case e switch-case-default.
A Figura 2.4 mostra que esses dois comandos rompem com o fluxo sequencial do código se uma determinada variável (Var) satisfizer algum dos casos base. Assim, se Var satisfizer o valor V1, então, o comando C1 será executado, se Var satisfizer o valor de V2, então, o comando C2 será executado, e assim sucessivamente. Nessa figura, C1, C2, C3, C4 e C5 indicam comandos a serem executados. No exemplo switch-case existe um fluxo unindo diretamente Var a C4, que será executado somente se nenhum dos casos for satisfeito. Já no exemplo switch-case-default, existe ao menos um comando dentro do switch que deverá ser executado; nesse exemplo, o comando C4 será executado se não for atendido nenhum dos casos anteriores, sendo assim, um comando padrão (default).
Você deve ter reparado certa semelhança entre a combinação de vários if-else encadeados e o switch-case. De forma geral, quando se tem três ou mais if-else seguidos e existe a possibilidade de se fazer a troca para um switch-case, essa troca é aconselhável.
A grande maioria dos programadores acha mais elegante e legível um código com switch-case do que com múltiplos if-else, além disso, o switch-case possui um desempenho ligeiramente melhor.
As estruturas básicas dos códigos dos comandos de decisão do tipo switch estão sintetizadas conforme o Quadro 2.5 a seguir.
Comando: switch-case |
Comando: switch-case-default |
---|---|
|
|
As variáveis de controle utilizadas dentro do switch podem ser dos seguintes tipos: byte, short, int, char e String. Nesse ponto, gostaríamos de desafiar o aluno a pensar e criar exemplos de aplicações que utilizam a estrutura de seleção múltipla com esses diversos tipos de dados mencionados.
Dentro do comando switch, no Quadro 2.5, foram utilizados diversos comandos break. O comando break, basicamente, interrompe o fluxo de execução dentro do comando switch. Dessa maneira, reflita sobre o que ocorre ao se esquecer de colocar o comando break em algum dos cases ou em todos os cases. Dica: faça a implementação do comando switch e não coloque o break; em seguida, reflita sobre o que ocorrerá.
Outro assunto importante a ser tratado diz respeito aos operadores aritméticos. Os principais operadores aritméticos presentes na linguagem Java são: soma (+), subtração (-), multiplicação (*), divisão (/) e resto da divisão (%). O funcionamento desses operadores é igual na linguagem C, e todos eles necessitam de dois operandos do tipo numérico e retornam um dado do tipo numérico. O Quadro 2.6 sintetiza algumas informações sobre os operadores aritméticos.
Nome Operador |
Símbolo |
Exemplo em Java | Exemplo Numérico |
---|---|---|---|
Soma | + | x + y | 5 + 3 (= 8) |
Subtração | - | x - y | 5 - 3 (= 2) |
Multiplicação | * | x * y | 5 * 3 (= 15) |
Divisão | / | x / y | 5 / 3 (= 1) |
Resto da divisão | % | x % y | 5 % 3 (= 2) |
Em relação ao Quadro 2.6, duas considerações são importantes: a primeira é sobre o operador da divisão: repare que no exemplo numérico, 5 / 3 deu resultado 1 e não 1.666..., mas por que isso ocorreu? A divisão de dois números inteiros é um valor inteiro, caso os valores numéricos fossem 5.0 / 3 ou 5 / 3.0 ou, ainda, 5.0 / 3.0, aí sim a resposta seria o valor 1.666..., pois o numerador ou o denominador é número em ponto flutuante. Outra consideração importante refere-se ao operador resto da divisão. Nesse operador, tanto o numerador quanto o denominador e o resultado devem ser números inteiros.
As regras de precedência de operadores em Java funcionam da seguinte forma:
Agora, quando aos operadores relacionais, os principais presentes na linguagem Java são: igualdade (==), diferente (!=), maior que (>), maior ou igual a (>=), menor que (<) e menor ou igual a (<=). O funcionamento desses operadores é igual na linguagem C. Todos eles necessitam de dois operandos de qualquer tipo e retornam um dado do tipo lógico (booleano). O Quadro 2.7 sintetiza algumas informações sobre os operadores relacionais.
Nome Operador |
Símbolo |
Exemplo em Java | Exemplo Numérico |
---|---|---|---|
Igualdade | == | x == y | 5 == 3 (falso) |
Diferente | != | x != y | 5 != 3 (verdade) |
Maior que | > | x > y | 5 > 3 (verdade) |
Maior ou igual a | >= | x >= y | 5 >= 3 (verdade) |
Menor que | < | x < y | 5 < 3 (falso) |
Menor ou igual a | <= | x <= y | 5 <= 3 (falso) |
As regras de precedência de operadores relacionais em Java são da seguinte forma:
Assim como a linguagem C, a linguagem Java também possui operadores de atribuição compostos, e os principais operadores de atribuição são: +=, -=, *=, /=, %=. O Quadro 2.8 sintetiza algumas informações sobre os operadores de atribuição compostos.
Nome do Operador |
Símbolo |
Exemplo Encurtado | Significado Exemplo |
---|---|---|---|
Atribuição de adição | += | x += 3 | x = x + 3 |
Atribuição de subtração | -= | x -= 3 | x = x - 3 |
Atribuição de multiplicação | *= | x *= 3 | x = x * 3 |
Atribuição de divisão | /= | x /= 3 | x = x / 3 |
Atribuição de resto | %= | x %= 3 | x = x % 3 |
Outro operador muito importante em Java é o operador de incremento e decremento que está sintetizado no Quadro 2.9. Esse é um operador unário, pois tem somente um operando.
Nome Operador |
Símbolo |
Exemplo em Java | Explicação do Exemplo |
---|---|---|---|
Pré-incremento | ++ | ++x | Incrementa x em 1 e, então, utiliza x na expressão atual. |
Pós-incremento | ++ | x++ | Utiliza x na expressão atual e, então, incrementa x em 1. |
Pré-decremento | -- | --x | Decrementa x em 1 e, então, utiliza x na expressão atual. |
Pós-decremento | -- | x-- | Utiliza x na expressão atual e, então, decrementa x em 1. |
Os principais operadores lógicos presentes em Java são: E lógico (&&), Ou Lógico (||), negação lógica (!). Os operadores E lógico e Ou lógico são operadores binários, já o operador negação lógico é um operador binário.
O Quadro 2.10 sintetiza os operadores lógicos presentes em Java.
Nome Operador |
Símbolo |
Exemplo em Java | Exemplo com Valores |
---|---|---|---|
E Lógico | && | exp1 && exp2 | true && false (falso) |
Ou Lógico | || | exp1 || exp2 | true || false (verdade) |
Negação Lógico | ! | !exp | !true (falso) |
Os operadores lógicos em Java são avaliados conforme as tabelas verdade da lógica matemática. Java faz uma avaliação dos valores lógicos chamada curto-circuito, em que a avaliação é interrompida assim que o valor global da expressão puder ser inferido. Por exemplo, caso o operador seja o E lógico e a primeira expressão seja falsa, então, o valor falso será retornado, pois, falso E, qualquer coisa é falsa; caso o operador seja o Ou lógico e a primeira expressão seja verdadeira, então, o valor verdadeiro será retornado, pois, verdadeiro Ou, qualquer coisa é verdadeira.
As regras de precedência de operadores lógicos em Java são da seguinte forma:
Outro ponto importante a ser abordado: os tipos de dados suportados. Java suporta dados do tipo primitivo e derivado.
Os tipos primitivos podem ser do tipo lógico, tipo carácter ou tipo numérico, que pode ser separado em dois grupos: o tipo inteiro e o tipo real (ou ponto flutuante). Eles podem ser classificados em: boolean, char, byte, short, int, long, float e double.
Os tipos de dados derivados podem ser de qualquer classe, como, por exemplo, String, Integer, Double, Array e Object.
A Figura 2.5 mostra a organização dos tipos de dados em Java.
É importante lembrar que, em Java, os tipos primitivos são passados para métodos por meio da passagem por valor ou cópia; já os tipos derivados são passados por meio da passagem por referência. Em Java, não se costuma falar em ponteiros, tal como na linguagem C, no entanto, vale lembrar que todas as variáveis do tipo derivado são, na verdade, referências (ponteiros) para uma instância da classe.
O Quadro 2.11 apresenta uma síntese com algumas informações dos tipos primitivos em Java. Neste quadro, foram destacados a quantidade de bits e bytes utilizada na representação dos tipos primitivos e os intervalos de valores dos dados.
Nome do Tipo |
Tamanho em bits |
Tamanho em bytes | Intervalo de Valores |
---|---|---|---|
boolean | 1 | - | true ou false |
char | 16 | 2 | 0 até 65535 ou '\u0000' até '\uffff' |
byte | 8 | 1 | -128 até 127 ou -27 até 27-1 |
short | 16 | 2 | -32.768 até 32.767 ou -215 até 215-1 |
int | 32 | 4 | -2.147.483.648 até 2.147.483.647 ou -231 até 231-1 |
long | 64 | 8 | -263 até 263 -1 |
float | 32 | 4 | 1.4e-45 até 3.4e+38 |
double | 64 | 8 | 4.9e-324 até 1.8e+308 |
Ter o hábito de consultar as classes da biblioteca padrão do Java é uma boa prática de programação. Essa consulta ajuda você a ter domínio de quais métodos construtores e constantes estão disponíveis para utilização e qual a sua assinatura. Acima, falamos dos tipos primitivos de dados presentes em Java, e você sabia que Java possui um tipo derivado equivalente a cada um dos tipos primitivos de dados? Esses tipos derivados são: Boolean, Character, Byte, Short, Integer, Long, Float e Double. Tendo isso em mente que tal dar uma olhada nessas classes?
Observação: uma forma de consultá-las é acessando cada uma diretamente pela IDE. Não é necessário ler toda a classe, o importante é ter uma visão geral e consultá-la sempre que necessário.
Assim como as estruturas de decisão, um outro assunto de extrema importância são as estruturas de repetição. A linguagem Java possui três estruturas de repetição principais, que são: for, while e do-while. A Figura 2.6 mostra de forma gráfica como ocorre o fluxo de execução em cada um desses comandos.
Na Figura 2.6, podemos perceber que esses três comandos criam laços que se repetem enquanto uma determinada condição (D1) é satisfeita, e assim que essa condição se torna falsa, o laço de repetição é interrompido. Ainda na Figura 2.6, V1 indica a inicialização de uma variável, C1 e C2 indicam comandos a serem executados e I1 indica o incremento de uma variável.
As estruturas dos comandos de repetição em nível de código podem ser sintetizadas conforme o Quadro 2.12 a seguir.
Comando: for |
Comando: while |
Comando: do-while |
---|---|---|
|
|
|
O comando for possui quatro partes principais, que são: inicialização de alguma variável de controle (indicada por Inicializ), avaliação de alguma expressão lógica (indicada por ExpLóg), incremento de alguma variável (indicado por Inc) e, por fim, a sequência de comandos que gostaríamos de executar (indicada por SeqDeComandosA). O comando while possui duas partes principais, que são: avaliação de uma expressão lógica no início e, em seguida, a sequência de comandos a serem executados. O comando do-while possui duas partes principais, que são: a sequência de comandos que serão executados e, somente no final, a avaliação da expressão lógica. Assim, a principal diferença do comando while para o do-while é que, no segundo, temos a garantia de que a sequência de comandos será executada pelo menos uma vez.
As estruturas de repetição estudadas acima são chamadas de estruturas iterativas. A linguagem Java suporta também estruturas recursivas que garantem também a repetição de alguma tarefa. A recursão em Java é feita assim como na linguagem C. Lembre-se de que todo código recursivo pode ser transformado em um código iterativo. O Quado 2.13 apresenta dois códigos para o cálculo do fatorial de um número inteiro n.
Exemplo fatorial iterativo |
Exemplo fatorial recursivo |
---|---|
|
|
Os códigos acima foram declarados como static, pois o fatorial não depende da classe em si. O resultado é um número inteiro do tipo long para se garantir o retorno do fatorial com 64 bits de precisão. Com esse tipo de dado, os valores de fatoriais de 0 a 20 serão calculados corretamente, pois cabem dentro da representação long. Para valores de n maiores que 20, ocorrem overflow e, assim, os resultados começam a não corresponder ao fatorial.
Faça a implementação dessas funções e execute diversos testes; avalie também valores de n maiores que 20 para entender mais sobre o overflow. Dica: veja o sinal do número retornado.
Caro aluno, acesse o link presente na seção Referências com o tema JavaTutor (Iterativo e Fatorial) e execute o código acompanhando a sua execução, linha a linha, para entendê-lo melhor.
O programador pode querer interromper todo o fluxo de um laço de repetição a qualquer momento ou, em vez disso, desejar interromper parte de um trecho de código dentro de um loop e ir diretamente para a estrutura de decisão; para tanto, a palavra reservada break e continue deverão ser utilizadas, respectivamente. Esses comandos break e continue funcionam de forma igual, tanto na linguagem Java quanto na linguagem C.
Caro estudante, nesta seção, você estudou os conteúdos relacionados às estruturas de decisão e de repetição, aos comandos if, if-else, ao operador ternário e switch, aos operadores aritméticos, relacionais e lógicos e, por fim, aos comandos for, while e do-while. Foi mostrado diversos exemplos sobre esses conceitos e como esses comandos são implementados em Java. Na seção seguinte, estudaremos melhor como funcionam os modificadores de acesso, o encapsulamento, a herança e o polimorfismo, avançando ainda mais no entendimento da linguagem Java.
ARANTES, J. da S. Github. 2020. Disponível em: https://bit.ly/3eiUMcF. Acesso em: 20 mai. 2020.
CAELUM. Java e orientação a objetos: curso FJ-11. [S.l.]: Caleum, [s.d.]. Disponível em: https://bit.ly/3iJX34d. Acesso em: 17 mai. 2020.
CURSO de Java #01 - História do Java - Gustavo Guanabara. [S.l.: s.n.], 2015. 1 vídeo (36 min). Publicado pelo canal Curso em Vídeo. Disponível em: https://bit.ly/2YvIJDZ. Acesso em: 22 jul. 2020.
DEITEL, P. J.; DEITEL, H. M. Java: como programar. 10. ed. São Paulo: Pearson Education, 2016.
GITHUB. 2020. Disponível em: https://bit.ly/2ZSr1ud. Acesso em: 21 jul. 2020.
LOIANE GRONER. Curso de Java 18: comandos break e continue. 2015. Disponível em: https://bit.ly/32lp8Yo. Acesso em: 20 jul. 2020.
ORACLE. Class Boolean. [s.d.] Disponível em: https://bit.ly/31rt76v. Acesso em: 20 jul. 2020.
ORACLE. Class Byte. [s.d.] Disponível em: https://bit.ly/3jfJDwu. Acesso em: 20 jul. 2020.
ORACLE. Class Character. [s.d.] Disponível em: https://bit.ly/2EfvEIb. Acesso em: 20 jul. 2020.
ORACLE. Class Double. [s.d.]. Disponível em: https://bit.ly/3jaYV5u. Acesso em: 20 jul. 2020.
ORACLE. Class Float. [s.d.]. Disponível em: https://bit.ly/3gweZgm. Acesso em: 20 jul. 2020.
ORACLE. Class Integer. [s.d.]. Disponível em: https://bit.ly/3lhp4BC. Acesso em: 20 jul. 2020.
ORACLE. Class Long. [s.d.]. Disponível em: https://bit.ly/34sFJw1. Acesso em: 20 jul. 2020.
ORACLE. Class Short. [s.d.]. Disponível em: https://bit.ly/2EufpGO. Acesso em: 20 jul. 2020.
PYTHON TUTOR. Java tutor - visualize Java code execution to learn Java online. [s.d.]. Disponível em: https://bit.ly/32s8S81. Acesso em: 20 jul. 2020.
SIERRA, K.; BATES, B. Use a cabeça! Java. 2. ed. Rio de Janeiro: Alta Books, 2005.