Skip to content

2. Noções básicas da linguagem Java

2.1. Introdução

Abordaremos o Java, inicialmente, como uma linguagem de programação clássica. Trataremos dos objetos posteriormente.

Em um programa, encontramos dois tipos de elementos

  • dados
  • as instruções que os manipulam

Geralmente, procuramos separar os dados das instruções:

Image

2.2. Os dados em Java

O Java utiliza os seguintes tipos de dados:

  • números inteiros
  • números reais
  • caracteres e cadeias de caracteres
  • booleanos
  • objetos

2.2.1. Tipos de dados predefinidos

Tipo
Codificação
Domínio
char
2 bytes
caractere Unicode
int
4 bytes
[-231, 231-1]
long
8 bytes
[-263, 263 -1]
byte
1 byte
[-27 , 27 -1]
short
2 bytes
[-215, 215-1]
float
4 bytes
[3.4 10-38, 3.4 10+38] em valor absoluto
double
8 bytes
[1.7 10-308 , 1.7 10+308] em valor absoluto
boolean
1 bit
verdadeiro, falso
String
referência do objeto
cadeia de caracteres
Date
referência de objeto
data
Character
referência do objeto
caractere
Integer
referência do objeto
int
Long
referência do objeto
long
Byte
referência do objeto
byte
Float
referência do objeto
float
Double
referência de objeto
double
Boolean
referência de objeto
booleano

2.2.2. Notação de dados literais

entier
145, -7, 0xFF (hexadecimal)
real duplo
134,789, -45E-18 (-45 × 10⁻¹⁸)
real float
134.789F, -45E-18F (-45 × 10⁻¹⁸)
caractère
'A', 'b'
cadeia de caracteres
"hoje"
booléen
verdadeiro, falso
date
new Date(13,10,1954) (dia, mês, ano)

2.2.3. Declaração de dados

2.2.3.1. Função das declarações

Um programa manipula dados caracterizados por um nome e um tipo. Esses dados são armazenados na memória. No momento da compilação do programa, o compilador atribui a cada dado um espaço na memória caracterizado por um endereço e um tamanho. Ele faz isso com base nas declarações feitas pelo programador.

Além disso, essas declarações permitem que o compilador detecte erros de programação. Assim, a operação

x = x * 2;

será declarada como errada se x for uma sequência de caracteres, por exemplo.

2.2.3.2. Declaração de constantes

A sintaxe para declarar uma constante é a seguinte:

final tipo nome=valor; //define a constante nome=valor

ex.: final float PI=3.141592F;

Observação

Por que declarar constantes?

  • A leitura do programa será mais fácil se dermos à constante um nome significativo:

ex.: final float taux_tva = 0.186F;

  • A modificação do programa será mais fácil caso a “constante” venha a mudar. Assim, no caso anterior, se a alíquota do IVA passar para 33%, a única alteração a ser feita será modificar a instrução que define seu valor:

final float taux_tva=0.33F;

Se tivéssemos usado 0,186 explicitamente no programa, seria necessário alterar várias instruções.

2.2.3.3. Declaração de variáveis

Uma variável é identificada por um nome e está associada a um tipo de dados. O nome de uma variável Java tem n caracteres, sendo o primeiro alfabético e os demais alfabéticos ou numéricos. O Java diferencia maiúsculas de minúsculas. Assim, as variáveis FIN e fin são diferentes.

As variáveis podem ser inicializadas no momento de sua declaração. A sintaxe para declarar uma ou mais variáveis é:

identificateur_de_type variable1,variable2,...,variablen;

onde identificateur_de_type é um tipo predefinido ou um tipo de objeto definido pelo programador.

2.2.4. As conversões entre números e cadeias de caracteres

número -> string
"" + número
cadeia -> int
Integer.parseInt(cadeia)
cadeia de caracteres -> long
Long.parseLong(string)
string -> double
Double.valueOf(string).doubleValue()
string -> float
Float.valueOf(string).floatValue()

Aqui está um programa que apresenta as principais técnicas de conversão entre números e cadeias de caracteres. A conversão de uma cadeia de caracteres em um número pode falhar se a cadeia não representar um número válido. Nesse caso, ocorre um erro fatal, chamado de exceção em Java. Esse erro pode ser tratado pela cláusula try/catch a seguir:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

Se a função não gerar uma exceção, passa-se para a instrução seguinte; caso contrário, passa-se para o corpo da cláusula catch e, em seguida, para a instrução seguinte. Voltaremos mais tarde ao gerenciamento de exceções.


import java.io.*;

public class conv1{

  public static void main(String arg[]){
    String S;
    final int i=10;
    final long l=100000;
    final float f=(float)45.78;
    double d=-14.98;

    // número --> string
    S=""+i;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);

    //booleano --> string
    final boolean b=false;
    S=""+new Boolean(b);
    affiche(S);

    // cadeia de caracteres --> int
    int i1;
    i1=Integer.parseInt("10");
    affiche(""+i1);
    try{
      i1=Integer.parseInt("10.67");
      affiche(""+i1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // string --> long
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // cadeia de caracteres --> double
    double d1;
    d1=Double.valueOf("100.87").doubleValue();
    affiche(""+d1);
    try{
      d1=Double.valueOf("abcd").doubleValue();
      affiche(""+d1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // cadeia de caracteres --> float
    float f1;
    f1=Float.valueOf("100.87").floatValue();
    affiche(""+f1);
    try{
      d1=Float.valueOf("abcd").floatValue();
      affiche(""+f1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

}// fim main

  public static void affiche(String S){
    System.out.println("S="+S);
  }
}// fim da classe

Os resultados obtidos são os seguintes:

S=10
S=100000
S=45.78
S=-14.98
S=false
S=10
S=Erreur java.lang.NumberFormatException: 10.67
S=100
S=Erreur java.lang.NumberFormatException: 10.675
S=100.87
S=Erreur java.lang.NumberFormatException: abcd
S=100.87
S=Erreur java.lang.NumberFormatException: abcd

2.2.5. As tabelas de dados

Uma matriz em Java é um objeto que permite agrupar, sob um mesmo identificador, dados do mesmo tipo. Sua declaração é a seguinte:

Tipo Tabela[] = new Tipo[n] ou Tipo[] Tabela = new Tipo[n]

Ambas as sintaxes são válidas. n é o número de dados que a matriz pode conter. A sintaxe Matriz[i] designa o dado nº i, onde i pertence ao intervalo [0,n-1]. Qualquer referência ao dado Tableau[i] em que i não pertença ao intervalo [0,n-1] provocará uma exceção.

Uma matriz bidimensional pode ser declarada da seguinte forma:

Tipo Tabela[][] = new Tipo[n][p] ou Tipo[][] Tabela = new Tipo[n][p]

A sintaxe Tableau[i] designa o dado nº i de Tableau, onde i pertence ao intervalo [0,n-1]. Tableau[i] é, por sua vez, uma tabela: Tableau[i][j] designa o dado nº j da Tabela[i], onde j pertence ao intervalo [0,p-1]. Qualquer referência a um dado de Tableau com índices incorretos gera um erro fatal.

Veja um exemplo:


public class test1{

  public static void main(String arg[]){
    float[][] taux=new float[2][2];
    taux[1][0]=0.24F;
    taux[1][1]=0.33F;
    System.out.println(taux[1].length);
    System.out.println(taux[1][1]);
  }
}

e os resultados da execução:

2
0.33

Um array é um objeto que possui o atributo length: trata-se do tamanho do array.

2.3. As instruções básicas do Java

Distinguem-se

  • as instruções elementares executadas pelo computador
  • as instruções de controle do andamento do programa.

As instruções elementares ficam claras quando se considera a estrutura de um microcomputador e de seus periféricos.

Image

  1. leitura de informações provenientes do teclado

  2. processamento de informações

  3. exibição de informações na tela

  4. leitura de informações de um arquivo em disco

  5. gravação de informações em um arquivo no disco

2.3.1. Gravação na tela

A sintaxe da instrução de gravação na tela é a seguinte:

System.out.println(expressão) ou System.err.println(expressão)

onde expression é qualquer tipo de dado que possa ser convertido em sequência de caracteres para ser exibido na tela. No exemplo anterior, vimos duas instruções de gravação:

System.out.println(taux[1].length);
System.out.println(taux[1][1]);

System.out grava em um arquivo de texto que, por padrão, é a tela. O mesmo se aplica a System.err. Esses arquivos possuem um número (ou descripteur) correspondente a 1 e 2, respectivamente. O fluxo de entrada do teclado (System.in) também é considerado um arquivo de texto, com o descritor 0. Tanto o DOS quanto o Unix suportam o uso de tubos (pipe) entre comandos:

    commande1 | commande2

Tudo o que o commande1 escreve com o System.out é redirecionado para a entrada do System.in do commande2. Em outras palavras, o commande2 lê, por meio do System.in, os dados produzidos pelo commande2 com o System.out, que, portanto, não são mais exibidos na tela. Esse sistema é amplamente utilizado no Unix. Nessa encadeamento de comandos, o fluxo System.err não é redirecionado: ele escreve na tela. É por isso que é usado para exibir mensagens de erro (daí seu nome err): assim, temos a garantia de que, durante um redirecionamento de comandos, as mensagens de erro continuarão sendo exibidas na tela. Portanto, é recomendável adquirir o hábito de exibir as mensagens de erro na tela usando o fluxo System.err, em vez do fluxo System.out.

2.3.2. Leitura de dados digitados no teclado

O fluxo de dados proveniente do teclado é designado pelo objeto System.in, do tipo InputStream. Esse tipo de objeto permite ler dados caractere por caractere. Cabe ao programador, então, identificar nesse fluxo de caracteres as informações de seu interesse. O tipo InputStream não permite ler uma linha de texto de uma só vez. O tipo BufferedReader permite isso com o método readLine.

Para poder ler linhas de texto digitadas no teclado, cria-se, a partir do fluxo de entrada System.in do tipo InputStream, outro fluxo de entrada, desta vez do tipo BufferedReader:

BufferedReader IN=new BufferedReader(new InputStreamReader(System.in));

Não explicaremos aqui os detalhes dessa instrução, que envolve o conceito de construção de objetos. Vamos utilizá-la tal como está.

A construção de um fluxo pode falhar: nesse caso, é gerado um erro fatal, chamado de exceção em Java. Sempre que um método pode gerar uma exceção, o compilador Java exige que ela seja tratada pelo programador. Portanto, para criar o fluxo de entrada anterior, será necessário, na verdade, escrever:


BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
        System.err.println("Erreur " +e);
        System.exit(1);
}

Mais uma vez, não vamos nos aprofundar aqui na gestão de exceções. Depois de criar o fluxo IN mencionado anteriormente, é possível ler uma linha de texto por meio da instrução:

    String ligne;
    ligne=IN.readLine();

A linha digitada no teclado é armazenada na variável ligne e pode, em seguida, ser utilizada pelo programa.

2.3.3. Exemplo de entradas e saídas

Aqui está um programa que ilustra as operações de entrada e saída do teclado e da tela:


import java.io.*;        // necessário para o uso de fluxos de E/S

public class io1{
  
  
  public static void main (String[] arg){
    
    // gravação no fluxo System.out
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // gravação no fluxo System.err
    int i=10;
    System.err.println("i="+i);
    
    // leitura de uma linha digitada no teclado
    String ligne;
    BufferedReader IN=null;
    try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }
    System.out.print("Tapez une ligne : ");
    try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
    }
  }//fim da entrada manual

  public static void affiche(Exception e){
    System.err.println("Erreur : "+e);
  }

}//fim de classe

e os resultados da execução:

C:\Serge\java\bases\iostream>java io1
java.lang.Object@1ee78b
java.lang.Object
i=10
Tapez une ligne : je suis là
ligne=je suis là

As instruções

Object obj=new Object();
System.out.println(""+obj);
System.out.println(obj.getClass().getName());

têm como objetivo mostrar que qualquer objeto pode ser exibido. Não vamos explicar aqui o significado do que está sendo exibido. Também temos a exibição do valor de um objeto no bloco:

try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }

A variável e é um objeto do tipo Exception, que é exibido aqui com a chamada affiche(e). Já havíamos encontrado, sem mencionar, essa exibição do valor de uma exceção no programa de conversão visto anteriormente.

2.3.4. Atribuição do valor de uma expressão a uma variável

Vamos nos concentrar aqui na operação variable=expression;

A expressão pode ser do tipo: aritmética, relacional, booleana, de caracteres

2.3.4.1. Interpretação da operação de atribuição

A operação variable=expression; é, por si só, uma expressão cuja avaliação ocorre da seguinte maneira:

  • A parte direita da atribuição é avaliada: o resultado é um valor V.
  • o valor V é atribuído à variável
  • o valor V é também o valor da atribuição, agora considerada como uma expressão.

É assim que a operação V1=V2=expressão é válida. Devido à prioridade, é o operador = mais à direita que será avaliado. Portanto, temos V1=(V2=expressão). A expressão V2=expressão é avaliada e tem como valor V. A avaliação dessa expressão provocou a atribuição de V a V2. O operador = seguinte é então avaliado na forma V1=V. O valor dessa expressão continua sendo V. Sua avaliação resulta na atribuição de V a V1. Assim, a operação V1=V2=expressão é uma expressão cuja avaliação

1: resulta na atribuição do valor de expression às variáveis V1 e V2

2: retorna como resultado o valor de expression.

É possível generalizar para uma expressão do tipo: V1=V2=....=Vn=expressão

2.3.4.2. Expressão aritmética

Os operadores das expressões aritméticas são os seguintes:

+: adição

  • : subtração

*: multiplicação

/: divisão: o resultado é o quociente exato se pelo menos um dos operandos for real. Se ambos os operandos forem inteiros, o resultado é o quociente inteiro. Assim, 5/2 → 2 e 5,0/2 → 2,5.

%: divisão: o resultado é o resto, independentemente da natureza dos operandos, sendo o quociente inteiro. Trata-se, portanto, da operação módulo.

Existem diversas funções matemáticas:

double sqrt(double x)
raiz quadrada
double cos(double x)
Cosseno
double sin(double x)
seno
double tan(double x)
Tangente
double pow(double x, double y)
x elevado a y (x > 0)
double exp(double x)
Exponencial
double log(double x)
Logaritmo natural
double abs(double x)
valor absoluto

etc...

Todas essas funções estão definidas em uma classe Java chamada Math. Ao utilizá-las, é necessário antepor o nome da classe em que estão definidas. Assim, escreveremos:

double x, y=4;
x=Math.sqrt(y);

A definição da classe Math é a seguinte:


public  final  class  java.lang.Math
    extends  java.lang.Object  (I-§1.12)
{
        // Campos
    public final static double E;    §1.10.1
    public final static double PI;    §1.10.2

        // Métodos
    public static double abs(double  a);    §1.10.3
    public static float abs(float  a);    §1.10.4
    public static int abs(int  a);    §1.10.5
    public static long abs(long  a);    §1.10.6
    public static double acos(double  a);    §1.10.7
    public static double asin(double  a);    §1.10.8
    public static double atan(double  a);    §1.10.9
    public static double atan2(double  a, double  b);    §1.10.10
    public static double ceil(double  a);    §1.10.11
    public static double cos(double  a);    §1.10.12
    public static double exp(double  a);    §1.10.13
    public static double floor(double  a);    §1.10.14
    public static double                        §1.10.15
        IEEEremainder(double  f1, double  f2);
    public static double log(double  a);    §1.10.16
    public static double max(double  a, double  b);    §1.10.17
    public static float max(float  a, float  b);    §1.10.18
    public static int max(int  a, int  b);    §1.10.19
    public static long max(long  a, long  b);    §1.10.20
    public static double min(double  a, double  b);     §1.10.21
    public static float min(float  a, float  b);    §1.10.22
    public static int min(int  a, int  b);    §1.10.23
    public static long min(long  a, long  b);    §1.10.24
    public static double pow(double  a, double  b);    §1.10.25
    public static double random();    §1.10.26
    public static double rint(double  a);    §1.10.27
    public static long round(double  a);    §1.10.28
    public static int round(float  a);    §1.10.29
    public static double sin(double  a);    §1.10.30
    public static double sqrt(double  a);    §1.10.31
    public static double tan(double  a);    §1.10.32
}

2.3.4.3. Prioridades na avaliação de expressões aritméticas

A prioridade dos operadores na avaliação de uma expressão aritmética é a seguinte (da mais alta à mais baixa):

[fonctions], [ ( )], [ *, /, %], [+, -]

Os operadores de um mesmo bloco [ ] têm a mesma prioridade.

2.3.4.4. Expressões relacionais

Os operadores são os seguintes: <, <=, ==, !=, >, >=

ordem de prioridade

>, >=, <, <=

==, !=

O resultado de uma expressão relacional é o valor booleano false se a expressão for falsa; true caso contrário.

Exemplo:

      boolean fin;
      int x;
      fin=x>4;

Comparação de dois caracteres

Sejam dois caracteres C1 e C2. É possível compará-los com os operadores

<, <=, ==, !=, >, >=

Nesse caso, são comparados seus códigos ASCII, que são números. Vale lembrar que, de acordo com a ordem ASCII, temos as seguintes relações:

espaço < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. < 'z'

Comparação de duas cadeias de caracteres

Elas são comparadas caractere por caractere. A primeira desigualdade encontrada entre dois caracteres determina uma desigualdade no mesmo sentido nas cadeias.

Exemplos:

Suponhamos que se queira comparar as cadeias “Gato” e “Cão”

Essa última desigualdade permite afirmar que “Gato” < “Cão”.

Image

Suponha que se queira comparar as cadeias “Gato” e “Gatinho”. Há igualdade o tempo todo até que a cadeia “Gato” se esgote. Nesse caso, a cadeia esgotada é declarada como a mais “pequena”. Portanto, temos a relação

“Gato” < “Gatinho”.

Funções de comparação entre duas cadeias

Não é possível utilizar aqui os operadores relacionais <, <=, ==, !=, >, >=. É necessário utilizar métodos da classe String:

String chaine1, chaine2;
chaine1=…;
chaine2=…;
int i=chaine1.compareTo(chaine2);
boolean egal=chaine1.equals(chaine2)

No exemplo acima, a variável i terá o valor:

0: se as duas cadeias forem iguais

1: se a sequência n.º 1 for maior que a sequência n.º 2

-1: se a sequência nº 1 for menor que a sequência nº 2

A variável egal terá o valor true se as duas cadeias forem iguais.

2.3.4.5. Expressões booleanas

Os operadores são & (and) ||(or) e ! (not). O resultado de uma expressão booleana é um valor booleano.

ordem de prioridade ! , &&, ||

exemplo:

int fin;
int x;
fin= x>2 && x<4;

Os operadores relacionais têm prioridade sobre os operadores && e ||.

2.3.4.6. Operações em bits

Os operadores

Sejam i e j dois números inteiros.

i<<n
desloca i n bits para a esquerda. Os bits de preenchimento são zeros.
i>>n
desloca i n bits para a direita. Se i for um inteiro com sinal (signed char, int, long), o bit de sinal é preservado.
i & j
realiza a operação lógica ET entre i e j, bit a bit.
i | j
realiza a operação lógica OU entre i e j, bit a bit.
~i
completa i com 1
i^j
gera OU a partir de EXCLUSIF de i e j

Ou seja

    int i=0x123F, k=0xF123;
    unsigned j=0xF123;
operação
valor
i<<4
0x23F0
i>>4
0x0123 o bit de sinal é preservado.
k>>4
0xFF12 o bit de sinal é preservado.
i&j
0x1023
i|j
0xF33F
~i
0xEDC0

2.3.4.7. Combinação de operadores

a=a+b pode ser escrito como a+=b

a=a-b pode ser escrito como a-=b

O mesmo se aplica aos operadores /, %, *, <<, >>, &, |, ^

Assim, a=a+2; pode ser escrito como a+=2;

2.3.4.8. Operadores de incremento e decremento

A notação variable++ significa variable=variable+1 ou ainda variable+=1

A notação variable-- significa variable=variable-1 ou ainda variable-=1.

2.3.4.9. O operador?

A expressão expr_cond ? expr1:expr2 é avaliada da seguinte maneira:

1: a expressão expr_cond é avaliada. Trata-se de uma expressão condicional com valor verdadeiro ou falso

2: Se for verdadeira, o valor da expressão é o de expr1. expr2 não é avaliada.

3: Se for falsa, ocorre o contrário: o valor da expressão é o de expr2. expr1 não é avaliada.

Exemplo

i = (j > 4 ? j + 1 : j - 1);

atribuirá à variável i:

j+1 se j>4, j-1 caso contrário

É o mesmo que escrever if(j>4) i=j+1; else i=j-1; mas é mais conciso.

2.3.4.10. Prioridade geral dos operadores

() [] função
gd
! ~ ++ --
dg
new (tipo) operadores de conversão
dg
* / %
gd
+ -
gd
<< >>
gd
< <= > >= instanceof
gd
== !=
gd
&
gd
^
gd
|
gd
&&
gd
||
gd
? :
dg
= += -= etc. .
dg

gd: indica que, em caso de igualdade de prioridade, é observada a regra de prioridade da esquerda para a direita. Isso significa que, quando em uma expressão há operadores com a mesma prioridade, o operador mais à esquerda na expressão é avaliado primeiro. dg indica uma prioridade da direita para a esquerda.

2.3.4.11. Mudanças de tipo

É possível, em uma expressão, alterar temporariamente a codificação de um valor. Isso é chamado de alteração do tipo de um dado ou, em inglês, type casting. A sintaxe para alterar o tipo de um valor em uma expressão é (tipo) valor. O valor passa então a ter o tipo indicado. Isso resulta em uma alteração na codificação do valor.

Exemplo:

int i, j;
float isurj;
isurj= (float)i/j;   // prioridade de () sobre /

Aqui é necessário alterar o tipo de i ou j para real; caso contrário, a divisão resultará em um quociente inteiro e não real.

i é um valor codificado com precisão em 2 bytes

(float) i é o mesmo valor codificado de forma aproximada como número real em 4 bytes

Portanto, ocorre uma transcodificação do valor de i. Essa transcodificação ocorre apenas durante o cálculo, já que a variável i mantém sempre seu tipo int.

2.4. As instruções de controle do andamento do programa

2.4.1. Parada

O método exit, definido na classe System, permite interromper a execução de um programa.

Sintaxe : void exit(int status)

ação: interrompe o processo em andamento e retorna o valor status ao processo pai

O método exit encerra o processo em andamento e devolve o controle ao processo chamador. O valor de *status pode ser utilizado por este. No DOS, essa variável status é retornada ao DOS na variável de sistema ERRORLEVEL, cujo valor pode ser verificado em um arquivo batch. No Unix, é a variável $? que recupera o valor de status* se o interpretador de comandos for o Bourne Shell (/bin/sh).

Exemplo:

    System.exit(0);

para encerrar o programa com um valor de status igual a 0.

2.4.2. Estrutura de escolha simples


 syntaxe :  if (condition) {actions_condition_vraie;} else {actions_condition_fausse;}

observações:

  • a condição está entre parênteses.
  • cada ação é terminada por ponto-e-vírgula.
  • As chaves não são encerradas por ponto-e-vírgula.
  • As chaves só são necessárias se houver mais de uma ação.
  • A cláusula else pode estar ausente.
  • Não há “then”.

O equivalente algorítmico dessa estrutura é a estrutura “se... então... senão”:

si condition
  alors actions_condition_vraie
  sinon actions_conditions_fausse
finsi

exemplo


    if (x>0)  { nx=nx+1;sx=sx+x;} else dx=dx-x;

É possível aninhar as estruturas de escolha:

if(condition1)
if (condition2)
        {......}
      else         //condição2
         {......}
else         //condição1
     {.......}

Às vezes surge o seguinte problema:


public static void main(void){
      int n=5;

   if(n>1)
     if(n>6)
             System.out.println(">6");
     else System.out.println("<=6");
}

No exemplo anterior, a referência else se refere a qual if? A regra é que um else sempre se refere ao if mais próximo: if(n>6), no exemplo. Consideremos outro exemplo:


public static void main(void)
{  int n=0;

   if(n>1)
     if(n>6)   System.out.println(">6");
     else;            // else do if(n>6): nada a fazer 
   else System.out.println("<=1");    // else do if(n>1) 
}

Aqui, queríamos colocar um else no if(n>1) e não um else no if(n>6). Devido à observação anterior, somos obrigados a incluir um else para o if(n>6), no qual não há nenhuma instrução.

2.4.3. Estrutura de casos

A sintaxe é a seguinte:

switch(expression) {
    case v1:     
            actions1;
            break;
    case v2:     
            actions2;
            break;
         . .. .. .. .. ..
    default:     actions_sinon;
}

notas

  • O valor da expressão de controle só pode ser um número inteiro ou um caractere.
  • A expressão de controle deve estar entre parênteses.
  • A cláusula default pode estar ausente.
  • Os valores vi são valores possíveis da expressão. Se a expressão tiver o valor vi, as ações associadas à cláusula case vi serão executadas.
  • A instrução break faz com que se saia da estrutura de caso. Se ela estiver ausente no final do bloco de instruções do valor vi, a execução prossegue com as instruções do valor vi+1.

Exemplo

Em algoritmos

selon la valeur de choix
cas 0
          arrêt
      cas 1
    exécuter module M1
  cas 2
    exécuter module M2
  sinon
    erreur<--vrai
findescas

Em Java


    int choix, erreur;
    switch(choix){   
        case 0: System.exit(0);
      case 1: M1();break;
      case 2: M2();break;
      default: erreur=1;
     }

2.4.4. Estrutura de repetição

2.4.4.1. Número de repetições conhecido

Sintaxe


    for (i=id;i<=if;i=i+ip){ 
       actions; 
      } 

Notas

  • Os três argumentos do for estão entre parênteses.
  • Os três argumentos do for são separados por ponto-e-vírgula.
  • Cada ação do for é terminada por um ponto-e-vírgula.
  • A chave só é necessária se houver mais de uma ação.
  • A chave não é seguida de ponto-e-vírgula.

O equivalente algorítmico é a estrutura pour:

pour i variant de id à if avec un pas de ip
        actions
finpour

que pode ser traduzida por uma estrutura tantque:

    i  id
    tantque i<=if
        actions
        i i+ip
    fintantque

2.4.4.2. Número de repetições desconhecido

Existem diversas estruturas em Java para esse caso.

Estrutura “while”


    while(condition){
          actions;
        } 

O loop continua enquanto a condição for verdadeira. O loop pode nunca ser executado.

Notas:

  • a condição está entre parênteses.
  • cada ação é terminada por ponto-e-vírgula.
  • A chave só é necessária se houver mais de uma ação.
  • A chave não é seguida de ponto-e-vírgula.

A estrutura algorítmica correspondente é a estrutura “enquanto”:

tantque condition
        actions
fintantque

Estrutura “repetir até” (do while)

A sintaxe é a seguinte:


    do{
       instructions;
    }while(condition); 

O loop é executado até que a condição se torne falsa ou enquanto a condição for verdadeira. Aqui, o loop é executado pelo menos uma vez.

notas

  • a condição está entre parênteses.
  • Cada ação é terminada por ponto-e-vírgula.
  • A chave só é necessária se houver mais de uma ação.
  • A chave não é seguida de ponto-e-vírgula.

A estrutura algorítmica correspondente é a estrutura “repetir … até”:

répéter
    actions
jusqu'à condition

Estrutura para “for”

A sintaxe é a seguinte:


for(instructions_départ;condition;instructions_fin_boucle){
    instructions; 
}

O loop é executado enquanto a condição for verdadeira (avaliada antes de cada iteração do loop). Instructions_départ são executadas antes de entrar no loop pela primeira vez. Instructions_fin_boucle são executadas após cada iteração do loop.

notas

  • Os três argumentos do for estão entre parênteses.
  • Os três argumentos do for são separados por ponto-e-vírgula.
  • Cada ação do for é terminada por um ponto-e-vírgula.
  • A chave só é necessária se houver mais de uma ação.
  • A chave não é seguida de ponto-e-vírgula.
  • As diferentes instruções em instructions_depart e instructions_fin_boucle são separadas por vírgulas.

A estrutura algorítmica correspondente é a seguinte:

instructions_départ
tantque condition
        actions
        instructions_fin_boucle
fintantque

Exemplos

Todos os programas a seguir calculam a soma dos primeiros n números inteiros.


1  for(i=1, somme=0;i<=n;i=i+1)
        somme=somme+a[i];

2     for (i=1, somme=0;i<=n;somme=somme+a[i], i=i+1);

3    i=1;somme=0;
    while(i<=n)
       { somme+=i; i++; }

4    i=1; somme=0;
    do somme+=i++;
         while (i<=n);

Instruções para gerenciamento de loop

break
sai do loop for, while, do ... while.
continue
avança para a próxima iteração dos loops for, while, do ... while

2.5. A estrutura de um programa Java

Um programa Java que não utilize classes definidas pelo usuário nem funções além da função principal main poderá ter a seguinte estrutura:


public class test1{
    public static void main(String arg[]){
        … code du programme
    }// main
}// class

A função main, também chamada de método, é executada em primeiro lugar durante a execução de um programa Java. Ela deve obrigatoriamente ter a assinatura a seguir:


    public static void main(String arg[]){

ou


    public static void main(String[] arg){

O nome do argumento arg pode ser qualquer um. Trata-se de uma matriz de cadeias de caracteres que representam os argumentos da linha de comando. Voltaremos a esse assunto mais adiante.

Se forem utilizadas funções suscetíveis de gerar exceções que não se deseja tratar detalhadamente, é possível envolver o código do programa em uma cláusula try/catch:


public class test1{
    public static void main(String arg[]){
        try{
        … code du programme
        } catch (Exception e){
            // gestão de erros
        }// try
    }// main
}// classe

No início do código-fonte e antes da definição da classe, é comum encontrar instruções de importação de classes. Por exemplo:


import java.io.*;
public class test1{
    public static void main(String arg[]){
        … code du programme
    }// main
}// classe

Vamos dar um exemplo. Considere a seguinte instrução de gravação:

System.out.println("java");

que exibe java na tela. Nessa instrução simples, há muitos elementos:

  • System é uma classe cujo nome completo é java.lang.System
  • out é uma propriedade dessa classe do tipo java.io.PrintStream, outra classe
  • println é um método da classe java.io.PrintStream.

Não vamos complicar desnecessariamente essa explicação, que surge muito cedo, já que requer a compreensão do conceito de classe, que ainda não foi abordado. Podemos comparar uma classe a um recurso. Neste caso, o compilador precisará ter acesso às duas classes java.lang.System e java.io.PrintStream. As centenas de classes do Java estão distribuídas em arquivos também chamados de pacotes (package). As instruções import colocadas no início do programa servem para indicar ao compilador de quais classes externas o programa precisa (aquelas utilizadas, mas não definidas no arquivo-fonte que será compilado). Assim, em nosso exemplo, nosso programa precisa das classes java.lang.System e java.io.PrintStream. Isso é indicado com a instrução import. Poderíamos escrever no início do programa:

import java.lang.System;
import java.io.PrintStream;

Como um programa Java costuma utilizar dezenas de classes externas, seria trabalhoso escrever todas as funções import necessárias. As classes foram agrupadas em pacotes, e assim é possível importar o pacote inteiro. Assim, para importar os pacotes java.lang e java.io, escrever-se-á:

import java.lang.*;
import java.io.*;

O pacote java.lang contém todas as classes básicas do Java e é importado automaticamente pelo compilador. Portanto, no final, basta escrever:

import java.io.*;

2.6. Gerenciamento de exceções

Muitas funções do Java podem gerar exceções, ou seja, erros. Já encontramos uma função desse tipo, a função readLine:


String ligne=null;
try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
}// try

Quando uma função pode gerar uma exceção, o compilador Java obriga o programador a tratá-la, com o objetivo de obter programas mais resistentes a erros: é preciso sempre evitar que um aplicativo “trave” de forma inesperada. Aqui, a função readLine gera uma exceção se não houver nada para ler, por exemplo, porque o fluxo de entrada foi fechado. O tratamento de uma exceção é feito de acordo com o esquema a seguir:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

Se a função não gerar uma exceção, passa-se para a instrução seguinte; caso contrário, passa-se para o corpo da cláusula catch e, em seguida, para a instrução seguinte. Observe os seguintes pontos:

  • e é um objeto derivado do tipo Exception. É possível ser mais preciso utilizando tipos como IOException, SecurityException, ArithmeticException, etc.: existem cerca de vinte tipos de exceções. Ao escrever catch (Exception e), indica-se que se deseja tratar todos os tipos de exceções. Se o código da cláusula try for suscetível de gerar vários tipos de exceções, pode-se querer ser mais preciso, tratando a exceção com várias cláusulas catch:

try{
    appel de la fonction susceptible de générer l'exception
} catch (IOException e){
    traiter l'exception e
}
} catch (ArrayIndexOutOfBoundsException e){
    traiter l'exception e
}
} catch (RunTimeException e){
    traiter l'exception e
}
instruction suivante
  • É possível adicionar uma cláusula `finally` às cláusulas try/catch:
try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
finally{
    code exécuté après try ou catch
}
instruction suivante

Aqui, haja ou não uma exceção, o código da cláusula finally será sempre executado.

  • A classe Exception possui um método getMessage() que retorna uma mensagem detalhando o erro ocorrido. Portanto, se quisermos exibir essa mensagem, escreveremos:
catch (Exception ex){
    System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
    ...
}//catch
  • A classe Exception possui um método toString() que retorna uma sequência de caracteres indicando o tipo da exceção, bem como o valor da propriedade Message. Assim, poderemos escrever:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

Também é possível escrever:

catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex);
    ...
}//catch

Temos aqui uma operação string + Exception que será automaticamente transformada em string + Exception.toString() pelo compilador, a fim de realizar a concatenação de duas cadeias de caracteres.

O exemplo a seguir mostra uma exceção gerada pelo uso de um elemento de tabela inexistente:

// quadros

// importações
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // declaração e inicialização de um array
    int[] tab=new int[] {0,1,2,3};
    int i;
     // exibição de tabela com um for
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // geração de uma exceção
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//main
}//classe

A execução do programa produz os seguintes resultados:

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
L'erreur suivante s'est produite : java.lang.ArrayIndexOutOfBoundsException

Aqui está outro exemplo em que se lida com a exceção causada pela atribuição de uma sequência de caracteres a um número, quando a sequência não representa um número:

// importações
import java.io.*;

public class console1{
  public static void main(String[] args){
      // criação de um fluxo de entrada
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // Solicitação do nome
    System.out.print("Nom : ");
     // leitura da resposta
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // solicitação da idade
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // pergunta
      System.out.print("âge : ");
       // Leitura e verificação da resposta
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // exibição final
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//classe

Alguns resultados da execução:

dos>java console1
Nom : dupont
âge : 23
Vous vous appelez dupont et vous avez 23 ans
E:\data\serge\MSNET\c#\bases\1>console1
Nom : dupont
âge : xx
Age incorrect, recommencez...
âge : 12
Vous vous appelez dupont et vous avez 12 ans

2.7. Compilação e execução de um programa Java

Compile e, em seguida, execute o seguinte programa:

// importação de classes
import java.io.*;

// classe de teste
public class coucou{
    // função main
  public static void main(String args[]){
      // exibição na tela
    System.out.println("coucou");
  }//main
}//classe

O arquivo de origem que contém a classe coucou anterior deve, obrigatoriamente, ser chamado de coucou.java:

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/2002  08:42                  228 coucou.java

A compilação e a execução de um programa Java são realizadas em uma janela DOS. Os executáveis javac.exe (compilador) e java.exe (interpretador) estão localizados no diretório bin do diretório de instalação do JDK:

E:\data\serge\JAVA\classes\paquetages\personne>dir "e:\program files\jdk14\bin\java?.exe"
07/02/2002  12:52               24 649 java.exe
07/02/2002  12:52               28 766 javac.exe

O compilador javac.exe analisará o arquivo-fonte .java e produzirá um arquivo compilado .class. Este não é imediatamente executável pelo processador. Ele requer um interpretador Java (java.exe), conhecido como máquina virtual ou JVM (Java Virtual Machine). A partir do código intermediário presente no arquivo .class, a máquina virtual irá gerar instruções específicas para o processador da máquina na qual ela está sendo executada. Existem máquinas virtuais Java para diferentes tipos de sistemas operacionais (Windows, Unix, Mac OS, etc.). Um arquivo .class pode ser executado por qualquer uma dessas máquinas virtuais e, portanto, em qualquer sistema operacional. Essa portabilidade entre sistemas é uma das principais vantagens do Java.

Vamos compilar o programa anterior:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\javac" coucou.java

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/2002  08:42                  228 coucou.java
10/06/2002  08:48                  403 coucou.class

Vamos executar o arquivo .class gerado:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\java" coucou
coucou

Observe-se que, na solicitação de execução acima, não foi especificado o sufixo .class do arquivo coucou.class a ser executado. Ele está implícito. Se o diretório bin do JDK estiver no PATH da máquina DOS, não será necessário especificar o caminho completo dos executáveis javac.exe e java.exe. Basta, então, escrever

javac coucou.java
java coucou

2.8. Argumentos do programa principal

A função principal main aceita como parâmetros uma matriz de strings: String[]. Essa matriz contém os argumentos da linha de comando usada para iniciar o aplicativo. Assim, se iniciarmos o programa P com o comando:

        java P arg0 arg1 … argn

e se a função main estiver declarada da seguinte forma:

public static void main(String[] arg);

teremos arg[0]="arg0", arg[1]="arg1" … Veja um exemplo:


import java.io.*;

public class param1{
  public static void main(String[] arg){
    int i;
    System.out.println("Nombre d'arguments="+arg.length);
    for (i=0;i<arg.length;i++)
      System.out.println("arg["+i+"]="+arg[i]);
  }
}

Os resultados obtidos são os seguintes:

dos>java param1 a b c
Nombre d'arguments=3
arg[0]=a
arg[1]=b
arg[2]=c

2.9. Passagem de parâmetros para uma função

Os exemplos anteriores mostraram apenas programas Java com uma única função, a função principal main. O exemplo a seguir mostra como utilizar funções e como ocorre a troca de informações entre elas. Os parâmetros de uma função são sempre passados por valor: ou seja, o valor do parâmetro efetivo é copiado para o parâmetro formal correspondente.


import java.io.*;

public class param2{
  public static void main(String[] arg){
    String S="papa";
    changeString(S);
    System.out.println("Paramètre effectif S="+S);
    int age=20;
    changeInt(age);
    System.out.println("Paramètre effectif age="+age);
  }
  private static void changeString(String S){
    S="maman";
    System.out.println("Paramètre formel S="+S);
  }
  private static void changeInt(int a){
    a=30;
    System.out.println("Paramètre formel a="+a);
  }
}

Os resultados obtidos são os seguintes:

Paramètre formel S=maman
Paramètre effectif S=papa
Paramètre formel a=30
Paramètre effectif age=20

Os valores dos parâmetros efetivos “papa” e 20 foram copiados para os parâmetros formais S e a. Estes foram, em seguida, modificados. Os parâmetros efetivos, por sua vez, permaneceram inalterados. É importante observar aqui o tipo dos parâmetros efetivos:

  • S é uma referência ao objeto c.a.d. O endereço de um objeto na memória
  • age é um valor inteiro

2.10. O exemplo dos impostos

Concluiremos este capítulo com um exemplo que será retomado várias vezes ao longo deste documento. Propomos escrever um programa que permita calcular o imposto de um contribuinte. Consideraremos o caso simplificado de um contribuinte que tenha apenas seu salário para declarar:

  • calcula-se o número de cotas do empregado nbParts = nbEnfants/2 + 1 se ele for solteiro, nbEnfants/2 + 2 se for casado, onde nbEnfants é o número de filhos.
  • se tiver pelo menos três filhos, ele tem mais meia parcela
  • calcula-se sua renda tributável R = 0,72 * S, onde S é seu salário anual
  • calcula-se seu coeficiente familiar QF = R / nbParts
  • calcula-se seu imposto I. Consideremos a tabela a seguir:
12620,0
0
0
13.190
0,05
631
15.640
0,1
1.290,5
24.740
0,15
2.072,5
31.810
0,2
3.309,5
39.970
0,25
4.900
48.360
0,3
6.898,5
55.790
0,35
9.316,5
92.970
0,4
12.106
127.860
0,45
16.754,5
151.250
0,50
23.147,5
172.040
0,55
30.710
195.000
0,60
39.312
0
0,65
49.062

Cada linha possui 3 campos. Para calcular o imposto I, procura-se a primeira linha em que QF ≤ campo1. Por exemplo, se QF = 23000, será encontrada a linha

    24740        0.15        2072.5

O imposto I é, então, igual a 0,15*R - 2072,5*nbParts. Se QF for tal que a relação QF <= campo1 nunca for verificada, então serão utilizados os coeficientes da última linha. Aqui:

    0                0.65        49062

o que resulta no imposto I = 0,65 * R - 49.062 * nbParts.

O programa Java correspondente é o seguinte:


import java.io.*;

public class impots{

    // ------------ main
    public static void main(String arg[]){

        // dados

        // limites das faixas de imposto
        double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // coeficiente aplicado ao número de cotas
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};

        // o programa

        // criação do fluxo de entrada do teclado
        BufferedReader IN=null;
        try{
            IN=new BufferedReader(new InputStreamReader(System.in));
        }
        catch(Exception e){
            erreur("Création du flux d'entrée", e, 1);
        }

            // recuperação do estado civil
        boolean OK=false;
        String reponse=null;
        while(! OK){
            try{
                System.out.print("Etes-vous marié(e) (O/N) ? ");
                reponse=IN.readLine();
                reponse=reponse.trim().toLowerCase();
                if (! reponse.equals("o") && !reponse.equals("n"))
                    System.out.println("Réponse incorrecte. Recommencez");
                else OK=true;
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }
        }
        boolean Marie = reponse.equals("o");

            // número de filhos
        OK=false;
        int NbEnfants=0; 
        while(! OK){
            try{
                System.out.print("Nombre d'enfants : ");
                reponse=IN.readLine();
                try{
                    NbEnfants=Integer.parseInt(reponse);
                    if(NbEnfants>=0) OK=true; 
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }// try
        }// while

        // salário
        OK=false;
        long Salaire=0; 
        while(! OK){
            try{
                System.out.print("Salaire annuel : ");
                reponse=IN.readLine();
                try{
                    Salaire=Long.parseLong(reponse);
                    if(Salaire>=0)  OK=true;
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture Salaire",e,4);
            }// try
        }// enquanto

            // cálculo do número de cotas
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
        
            // renda tributável
        double Revenu;
        Revenu=0.72*Salaire;

            // quociente familiar
        double QF;
        QF=Revenu/NbParts;
        
            // busca da faixa de imposto correspondente a QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // o imposto
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);

        // exibe-se o resultado
        System.out.println("Impôt à payer : " + impots);
    }// página inicial

    // ------------ erro
    private static void erreur(String msg, Exception e, int exitCode){
        System.err.println(msg+"("+e+")");
        System.exit(exitCode);
    }// erro

}// classe

Os resultados obtidos são os seguintes:

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : 3
Salaire annuel : 200000
Impôt à payer : 16400

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? n
Nombre d'enfants : 2
Salaire annuel : 200000
Impôt à payer : 33388

C:\Serge\java\impots\1>java impots

Etes-vous marié(e) (O/N) ? w
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? q
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? o
Nombre d'enfants : q
Réponse incorrecte. Recommencez
Nombre d'enfants : 2
Salaire annuel : q
Réponse incorrecte. Recommencez
Salaire annuel : 1
Impôt à payer : 0