3.5. Ainda as expressões

3.5.1. Avaliação de expressões. Precedências.

Devemos ter em atenção a ordem pela qual as operações são avaliadas numa expressão. O produto e a divisão, por exemplo, têm prioridade sobre a soma e a subtração.

Se queremos contrariar as prioridades definidas para as operações no Java, temos que usar parentesis.

Quando numa expressão temos vários operadores associativos com igual precedência (por exemplo, + e - e *, / e %), a ordem de avaliação é da esquerda para a direita – por exemplo, 6 + 4 - 3 é equivalente a (6 + 4) - 3. Considere o seguinte programa:

Na quarta instrução temos uma atribuição do valor inteiro 10 a uma variável do tipo double. Isto é possível – o que o computador faz é uma conversão automática do literal inteiro 10 para double e a sua atribuição à variável d2. O contrário não é possível, ou seja, atribuir um valor do tipo double a uma variável do tipo int (o que é lógico, se pensarmos bem).

No cálculo da expressão a atribuir à variável expr1, a primeira operação a ser feita é a divisão de i (cujo valor é 2) por 4 (que dá 0); repare que a divisão que é feita é a divisão inteira, porque tanto i como 4 são do tipo int; a seguir, dado que a soma e a subtração têm a mesma prioridade e as operações são associativas à esquerda, é feita a soma de 5 com j (que dá 11) e, finalmente, a subtração de 11 e 0 que dá 11.

No cálculo da expressão a atribuir à variável expr2, porque o uso de parentesis muda as prioridades, a primeira operação a ser feita é a subtração j – i (que dá 4); a seguir, uma vez que a divisão tem maior prioridade que a soma, é feita a divisão inteira entre 4 e 4 (que dá 1) e, finalmente, a soma de 5 e 1 que dá 6.

No cálculo da expressão a atribuir à variável expr3, a primeira operação a ser feita é também j – i (que dá 4) mas de seguida é feita a soma desse valor com 5, o que dá 9. Finalmente, é avaliada a divisão inteira de 9 por 4 que dá 2.

Qual o valor atribuído à variável d3? 1.5? 1.0? Se respondeu 1.0 acertou! Embora a variável seja do tipo double, a expressão j / 4 é uma divisão entre dois valores do tipo int (j é int e 4 é um literal do tipo int), logo a divisão que é feita é a divisão inteira, que resulta no inteiro 1, o qual é de seguida automaticamente convertido para double e atribuído à variável d3.

A variável d4 já ficará com o valor 1.5 pois a divisão que é efetuada entre j e 4.0 já é a divisão real – um dos operandos não é inteiro (4.0 é um literal do tipo double).

A variável s3 ficará com o valor "Oh Alcibiades, jah viste o Briolanjo hoje?" ; quando a expressão "Oh " + s1 + ", jah viste o " + s2 + " hoje? " é avaliada, é feita a concatenação de todas as strings nela presentes; s1 e s2, por serem variáveis, representam o seu conteúdo e é esse conteúdo que vai ser usado na avaliação da expressão.

NOTA: Como já deve ter percebido, uma expressão não é uma instrução! Uma expressão representa um valor que é o resultado da sua avaliação. E esse valor deve ser usado para algum objetivo concreto como, por exemplo, ser atribuído a uma variável ou ser escrito no ecrã. Não faz sentido, então, ter uma expressão sózinha no lugar de uma instrução pois, desse modo, nada é feito com o seu valor, depois de avaliada.

3.5.2. Conversão de double para int

O Java converte int para double automaticamente sempre que necessário, como já vimos acima, pois não se perde nenhuma informação no processo. Por outro lado, para converter double para int é necessário fazer algo com a parte decimal, a qual não é representável num inteiro.

O Java não faz isto automaticamente porque é importante que o programador fique ciente da perda dessa parte decimal e também para que seja ele a decidir o que fazer a essa parte decimal – se arredondar ou se truncar (cortar).

Há várias formas de fazer esta conversão, mas para já vamos só ver a mais simples e direta: usar cast de tipos. A forma de obter o cast de tipos é colocar o nome do tipo alvo da conversão entre parêntesis à frente da expressão que se pretende converter.

A primeira das instruções seguintes declara e inicializa uma variável pi do tipo double; a segunda instrução converte o valor da variável pi para int truncando a parte decimal e atribui esse valor inteiro à variável k – a variável k ficará com o valor 3. O conteúdo da variável pi não é afetado!

Na terceira instrução a variável x fica com o valor 60.9.

O operador de cast tem maior precedência do que a multiplicação (na verdade, maior do que de todos os operadores binários) e, por isso, se quisermos converter o resultado de uma expressão, temos que aplicar o cast sobre essa expressão entre parêntesis.

Com a instrução double y = (int) (pi * 20.3);, a variável y fica com o valor 63.0 – a expressão pi * 20.3, quando avaliada, tem o valor 63.774277 que, truncado pelo cast, fica 63.0.

3.5.3. Ainda a concatenação de Strings

Já vimos que o operador +, quando usado com valores do tipo String, resulta na concatenação dos seus operandos. Quando este operador é usado com uma String e um valor de outro tipo, o resultado é uma String.

O seguinte excerto de programa:

produz o seguinte output:

Os valores atribuídos às variáveis info1 a info4 são iguais, embora tenham sido construídos de forma diferente.

Repare que a expressão à direita da atribuição à variável info2 tem dois operadores iguais, de concatenação; por serem iguais, são avaliados da esquerda para a direita. Na primeira operação, como um dos operandos é do tipo String, o operador + é interpretado como concatenação; é feita então como que uma conversão do inteiro 12 em String antes da concatenação ser avaliada. O valor resultante dessa primeira concatenação é a String "Maria tem 12" que, de seguida, é concatenada com a string " anos", resultando em "Maria tem 12 anos".

Na atribuição à variável info3Parcial o esquema de avaliação é o mesmo, com a diferença de que o valor que é concatenado com a String "Maria tem " é dado por uma variável. É o valor da variável que é usado na concatenação.

A atribuição à variável info3 é uma concatenação vulgar entre duas Strings, em que uma é dada pelo conteúdo da variável info3Parcial.

3.5.4. Funções matemáticas

À semelhança das expressões matemáticas, podemos incluir numa expressão Java algumas das funções matemáticas mais comuns. Para já, vamos ver só alguns exemplos de como fazer isso; uma explicação mais aprofundada das funções em geral fica para o próximo capítulo.

As funções Math.sqrt, Math.sin e Math.round calculam, respetivamente, a raiz quadrada, o seno e o valor arredondado do seu argumento. A função Math.exp calcula o número de Euler, e, elevado ao seu argumento.

No cálculo do valor de uma função, é feita, em primeiro lugar, a avaliação dos seus argumentos e, de seguida então, a avaliação da função sobre esses valores (na segunda instrução é calculado primeiro o valor de 17.0 * i e de seguida então a raiz quadrada desse resultado).

Na expressão da última instrução temos composição de funções – como o resultado de uma função aplicada a um valor é ele próprio um valor, pode ser usado como argumento de outra função.

Quando queremos usar no nosso programa um valor (pseudo)aleatório, podemos usar a função Math.random, cujo resultado é um número aleatório do tipo double, no intervalo [0,1[. Por exemplo, double umQualquer = Math.random();

Se quisermos um número aleatório num intervalo diferente desse, basta-nos fazer as operações necessárias para o efeito. Como exemplo, a instrução double entre25e50 = (Math.random() + 1) * 25; gera um valor aleatório no intervalo [25,50[ e atribui esse valor à variável entre25e50.

Ver em https://docs.oracle.com/javase/9/docs/api/java/lang/Math.html as funções disponíveis mais comuns.

 


Anterior: 3.4. Revisitando variáveis

Seguinte: 3.6. Comentários, indentação e outros promotores da legibilidade