2. Os fundamentos da linguagem Java
2.1. Introdução
Vamos, em primeiro lugar, abordar o Java como uma linguagem de programação tradicional. Abordaremos os objetos mais tarde.
Num programa, existem duas coisas
- dados
- as instruções que os manipulam
Geralmente, procuramos separar os dados das instruções:

2.2. Dados Java
O Java utiliza os seguintes tipos de dados:
- inteiros
- números de ponto flutuante
- caracteres e cadeias de caracteres
- booleanos
- objetos
2.2.1. Tipos de dados predefinidos
Tipo | Codificação | Intervalo |
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 | [-2(15), 2(15),-1] |
float | 4 bytes | [3,410⁻³⁸, 3,410³⁸] em valor absoluto |
duplo | 8 bytes | [1,7 × 10⁻³⁰⁸, 1,7 × 10³⁰⁸] em valor absoluto |
booleano | 1 bit | verdadeiro, falso |
String | referência a objeto | string |
Data | referência a objeto | data |
Caractere | referência a objeto | caractere |
Inteiro | referência a objeto | int |
Long | referência a objeto | long |
Byte | referência a objeto | byte |
Float | referência a objeto | float |
duplo | referência a objeto | double |
Booleano | referência a objeto | Booleano |
2.2.2. Notação de dados literais
inteiro | 145, -7, 0xFF (hexadecimal) |
duplo | 134,789, -45E-18 (-45 × 10⁻¹⁸) |
flutuante | 134,789F, -45E-18F (-45 × 10⁻¹⁸) |
caractere | 'A', 'b' |
string | "hoje" |
booleano | verdadeiro, falso |
data | new Date(13,10,1954) (dia, mês, ano) |
2.2.3. Declaração de dados
2.2.3.1. Papel das declarações
Um programa manipula dados caracterizados por um nome e um tipo. Estes dados são armazenados na memória. Quando o programa é compilado, o compilador atribui a cada dado um local na memória caracterizado por um endereço e um tamanho. Faz isso utilizando as declarações feitas pelo programador.
Além disso, estas declarações permitem ao compilador detetar erros de programação. Assim, a operação
x=x*2;
será declarada incorreta se x for uma cadeia de caracteres, por exemplo.
2.2.3.2. Declaração de Constantes
A sintaxe para declarar uma constante é a seguinte:
<mark style="background-color: #ffff00">tipo</mark>**<mark style="background-color: #ffff00"> final </mark>**<mark style="background-color: #ffff00">nome=valor; </mark> //define constante nome=valor
ex: final float PI=3.141592F;
Nota
Por que declarar constantes?
- O programa será mais fácil de ler se for atribuído um nome significativo à constante:
ex: *final float VAT\_rate=0.186F*;
- A modificação do programa será mais fácil se for necessário alterar a «constante». Assim, no caso anterior, se a taxa de IVA passar para 33%, a única modificação necessária será alterar a instrução que define o seu valor:
*final float taxa\_imposto=0.33F*;
Se tivéssemos utilizado explicitamente 0,186 no programa, teríamos então de modificar inúmeras instruções.
2.2.3.3. Declaração de variáveis
Uma variável é identificada por um nome e refere-se a um tipo de dados. Um nome de variável Java é composto por n caracteres, sendo que o primeiro deve ser uma letra e os restantes podem ser letras ou números. O Java distingue entre letras maiúsculas e minúsculas. Assim, as variáveis FIN e fin são diferentes.
As variáveis podem ser inicializadas quando são declaradas. A sintaxe para declarar uma ou mais variáveis é:
onde identificador_de_tipo é um tipo predefinido ou um tipo de objeto definido pelo programador.
2.2.4. Conversões entre números e cadeias de caracteres
número -> cadeia | "" + número |
cadeia -> int | Integer.parseInt(cadeia de caracteres) |
cadeia -> long | Long.parseLong(cadeia) |
string -> double | Double.valueOf(string).doubleValue() |
string -> float | Float.valueOf(string).floatValue() |
Aqui está um programa que demonstra as principais técnicas para converter entre números e cadeias de caracteres. A conversão de uma cadeia de caracteres num número pode falhar se a cadeia não representar um número válido. Isto resulta num erro fatal, conhecido como exceção em Java. Este erro pode ser tratado utilizando o seguinte bloco try/catch:
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 lançar uma exceção, o programa prossegue para a instrução seguinte; caso contrário, entra no corpo da cláusula catch e, em seguida, prossegue para a instrução seguinte. Voltaremos ao tratamento de exceções mais tarde.
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;
// number --> string
S=""+i;
affiche(S);
S=""+l;
affiche(S);
S=""+f;
affiche(S);
S=""+d;
affiche(S);
//boolean --> string
final boolean b=false;
S=""+new Boolean(b);
affiche(S);
// string --> 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);
}
// chain --> 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);
}
// string --> 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);
}
}// fine hand
public static void affiche(String S){
System.out.println("S="+S);
}
}// end of class
Os resultados 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. Matrizes de dados
Uma matriz Java é um objeto que permite agrupar dados do mesmo tipo sob um único identificador. É declarada da seguinte forma:
Tipo Matriz[] = new Tipo[n] ou Tipo[] Matriz = new Tipo[n]
Ambas as sintaxes são válidas. n é o número de elementos que a matriz pode conter. A sintaxe Array[i] refere-se ao elemento no índice i, onde i está no intervalo [0,n-1]. Qualquer referência ao elemento Array[i] em que i não esteja no intervalo [0,n-1] causará uma exceção.
Uma matriz bidimensional pode ser declarada da seguinte forma:
Type Array[][] = new Type[n][p] ou Type[][] Array = new Type[n][p]
A sintaxe Array[i] refere-se ao elemento de dados i de Array, onde i pertence ao intervalo [0,n-1]. Array[i] é, por si só, uma matriz: Array[i][j] refere-se ao j-ésimo elemento de Array[i], onde j pertence ao intervalo [0,p-1]. Qualquer referência a um elemento de Array com índices incorretos gera um erro fatal.
Eis 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:
Uma matriz é um objeto com um atributo «length»: este é o tamanho da matriz.
2.3. Comandos básicos de Java
Distinguimos
- as instruções básicas executadas pelo computador.
- instruções que controlam o fluxo do programa.
As instruções básicas tornam-se claras quando se considera a estrutura de um microcomputador e dos seus periféricos.

-
Leitura de informações a partir do teclado
-
Processamento de informação
-
Gravação de informações no ecrã
-
Ler informações de um ficheiro em disco
-
Gravar informações num ficheiro em disco
2.3.1. Escrever no ecrã
A sintaxe da instrução de saída para o ecrã é a seguinte:
System.out.println(expressão) ou System.err.println(expressão)
onde expressão é qualquer tipo de dados que possa ser convertido numa cadeia de caracteres para ser apresentado no ecrã. No exemplo anterior, vimos duas instruções de impressão:
O System.out escreve num ficheiro de texto, que por predefinição é o ecrã. O mesmo se aplica ao System.err. A estes ficheiros são atribuídos os números (ou descritores) 1 e 2, respetivamente. O fluxo de entrada do teclado (System.in) também é tratado como um ficheiro de texto, com o descritor 0. Tanto o DOS como o Unix suportam o encadeamento de comandos:
Tudo o que o comando1 escreve no System.out é canalizado (redirecionado) para a entrada System.in do comando2. Por outras palavras, o comando2 lê no System.in os dados produzidos pelo comando2 através do System.out, que, por isso, já não são apresentados no ecrã. Este sistema é amplamente utilizado no Unix. Neste encadeamento, o fluxo System.err não é redirecionado: ele escreve no ecrã. É por isso que é utilizado para escrever mensagens de erro (daí o seu nome err): podemos ter a certeza de que, quando os comandos são encadeados, as mensagens de erro continuarão a aparecer no ecrã. Devemos, portanto, adquirir o hábito de escrever mensagens de erro no ecrã utilizando o fluxo System.err em vez do fluxo System.out.
2.3.2. Ler dados digitados no teclado
O fluxo de dados proveniente do teclado é representado pelo objeto System.in, do tipo InputStream. Este tipo de objeto permite que os dados sejam lidos caractere a caractere. Cabe ao programador extrair as informações relevantes desse fluxo de caracteres. O tipo InputStream não permite que uma linha de texto seja lida de uma só vez. O tipo BufferedReader permite isso através do método readLine.
Para ler linhas de texto introduzidas através do teclado, criamos um novo fluxo de entrada do tipo BufferedReader a partir do fluxo de entrada System.in* do tipo InputStream*:
Não explicaremos aqui os detalhes desta instrução, uma vez que envolve o conceito de construção de objetos. Iremos utilizá-la tal como está.
A criação de um fluxo pode falhar: é então gerado um erro fatal, chamado de exceção em Java. Sempre que um método é suscetível de gerar uma exceção, o compilador Java exige que esta seja tratada pelo programador. Portanto, para criar o fluxo de entrada anterior, temos de escrever, na verdade:
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 entraremos em detalhes sobre o tratamento de exceções aqui. Assim que o fluxo IN anterior tiver sido criado, podemos ler uma linha de texto utilizando a instrução:
A linha digitada no teclado é armazenada na variável ligne e pode então ser utilizada pelo programa.
2.3.3. Exemplo de Entrada/Saída
Aqui está um programa que ilustra operações de entrada/saída do teclado/ecrã:
import java.io.*; // required to use I/O streams
public class io1{
public static void main (String[] arg){
// write to System.out stream
Object obj=new Object();
System.out.println(""+obj);
System.out.println(obj.getClass().getName());
// write to System.err stream
int i=10;
System.err.println("i="+i);
// reading a line entered on the keyboard
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);
}
}//fine hand
public static void affiche(Exception e){
System.err.println("Erreur : "+e);
}
}//end of class
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
destinam-se a mostrar que qualquer objeto pode ser exibido. Não tentaremos aqui explicar o significado do que é exibido. Temos também 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 Exception que é exibido aqui através da chamada display(e). Encontrámos esta exibição do valor de uma exceção no programa de conversão visto anteriormente, embora não o tenhamos discutido na altura.
2.3.4. Atribuir o valor de uma expressão a uma variável
Aqui, estamos interessados na operação variável=expressão;
A expressão pode ser dos seguintes tipos: aritmética, relacional, booleana, cadeia de caracteres
2.3.4.1. Interpretação da operação de atribuição
A operação variável=expressão; é, ela própria, uma expressão cuja avaliação decorre da seguinte forma:
- O lado direito da atribuição é avaliado: 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.
É por isso que a expressão V1=V2=expressão é válida. Devido à precedência, o operador = mais à direita será avaliado. Temos, portanto, V1=(V2=expressão). A expressão V2=expressão é avaliada e tem o valor V. A avaliação desta expressão fez com que V fosse atribuído a V2. O operador = seguinte é então avaliado como V1=V. O valor desta expressão continua a ser V. A sua avaliação faz com que V seja atribuído a V1. Assim, a operação V1=V2=expressão é uma expressão cuja avaliação
1: faz com que o valor de expressão seja atribuído às variáveis V1 e V2
2: retorna o valor de expressão como resultado.
Podemos generalizar isto para uma expressão da forma: V1=V2=....=Vn=expressão
2.3.4.2. Expressão aritmética
Os operadores para 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 um número inteiro. Trata-se, portanto, da operação módulo.
Existem várias funções matemáticas:
double sqrt(double x) | raiz quadrada |
double cos(double x) | cosseno |
double sin(double x) | seno |
tan(x) | Tangente |
double potência(double x, double y) | x elevado a y (x > 0) |
exp(x) | Exponencial |
double log(double x) | Logaritmo natural |
double abs(double x) | valor absoluto |
etc...
Todas estas funções estão definidas numa classe Java chamada Math. Ao utilizá-las, deve antepor-lhes o nome da classe em que estão definidas. Assim, escreveria:
A definição da classe Math é a seguinte:
public final class java.lang.Math
extends java.lang.Object (I-§1.12)
{
// Fields
public final static double E; §1.10.1
public final static double PI; §1.10.2
// Methods
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. Operadores na avaliação de expressões aritméticas
A precedência dos operadores na avaliação de uma expressão aritmética é a seguinte (da mais alta para a mais baixa):
[funções], [ ( )], [ *, /, %], [+, -]
Os operadores dentro do mesmo bloco [ ] têm a mesma precedência.
2.3.4.4. Operadores relacionais
Os operadores são os seguintes: <, <=, ==, !=, >, >=
Ordem de precedência
>, >=, <, <=
==, !=
O resultado de uma expressão relacional é o valor booleano falso se a expressão for falsa; caso contrário, é verdadeiro.
Exemplo:
Comparação de dois caracteres
Suponha que existam dois caracteres C1 e C2. Estes podem ser comparados utilizando os operadores
<, <=, ==, !=, >, >=
Neste caso, os seus códigos ASCII — que são números — são comparados. Recorde-se que, de acordo com a ordem ASCII, verificam-se as seguintes relações:
espaço < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. < 'z'
Comparação de duas cadeias de caracteres
São comparadas caractere a caractere. A primeira desigualdade encontrada entre dois caracteres resulta numa desigualdade na mesma direção para as cadeias.
Exemplos:
Considere a comparação das cadeias de caracteres «Cat» e «Dog»
Esta última desigualdade permite-nos concluir que «Cat» < «Dog».

Considere comparar as cadeias "Cat" e "Kitten". São iguais em toda a sua extensão até que a cadeia "Cat" se esgote. Neste caso, a cadeia esgotada é declarada como a "menor". Temos, portanto, a relação
«Cat» < «Kitten».
Funções para comparar duas cadeias de caracteres
Não podemos usar os operadores relacionais <, <=, ==, !=, >, >= aqui. Temos de usar métodos da classe String:
String chaine1, chaine2;
chaine1=…;
chaine2=…;
int i=chaine1.compareTo(chaine2);
boolean egal=chaine1.equals(chaine2)
No código acima, a variável i terá o valor:
0: se as duas cadeias forem iguais
1: se a string 1 > string 2
-1: se a string 1 for menor que a string 2
A variável equal terá o valor true se as duas cadeias forem iguais.
2.3.4.5. Expressões booleanas
Os operadores são & (e), || (ou) e ! (não). O resultado de uma expressão booleana é um valor booleano.
Ordem de precedência ! , &&, ||
exemplo:
Os operadores relacionais têm precedência sobre os operadores && e ||.
2.3.4.6. Operações bit a bit
Os operadores
Sejam i e j dois números inteiros.
i<<n | desloca i n bits para a esquerda. Os bits resultantes 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 AND entre i e j, bit a bit. |
i | j | Realiza a operação lógica OR entre i e j, bit a bit. |
~i | complementa i para 1 |
i^j | realiza o XOR de i e j |
Seja
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 variable+=1
A notação variable-- significa variable=variable-1 ou variable-=1.
2.3.4.9. O operador ?
A expressão expr_cond ? expr1:expr2 é avaliada da seguinte forma:
1: A expressão expr_cond é avaliada. Trata-se de uma expressão condicional com um valor verdadeiro ou falso
2: Se for verdadeiro, o valor da expressão é o de expr1. expr2 não é avaliada.
3: Se for falso, 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
Isto é o mesmo que escrever if(j>4) i=j+1; else i=j-1; mas é mais conciso.
2.3.4.10. Ordem de precedência geral dos operadores
() [] função | gd |
! ~ ++ -- | dg |
novos operadores de conversão de tipos | dg |
* / % | gd |
+ - | gd |
<< >> | gd |
< <= > >= instanceof | gd |
== != | gd |
& | gd |
^ | gd |
| | gd |
&& | gd |
|| | gd |
? : | dg |
= += -= etc. . | dg |
gd: indica que, para operadores de igual precedência, é observada a precedência da esquerda para a direita. Isto significa que, quando uma expressão contém operadores da mesma precedência, o operador mais à esquerda na expressão é avaliado primeiro. dg indica precedência da direita para a esquerda.
2.3.4.11. Conversão de tipos
É possível, dentro de uma expressão, alterar temporariamente a representação de um valor. Isto é chamado de conversão de tipos. A sintaxe para alterar o tipo de um valor numa expressão é (tipo) valor. O valor assume então o tipo especificado. Isto resulta numa alteração na representação do valor.
Exemplo:
Aqui, é necessário converter i ou j para um tipo de ponto flutuante; caso contrário, a divisão retornará um quociente inteiro em vez de um valor de ponto flutuante.
*i* é um valor codificado exatamente em 2 bytes
*(float) i* é o mesmo valor, codificado aproximadamente como um número de ponto flutuante em 4 bytes
Existe, portanto, uma conversão de tipo do valor de i. Esta conversão ocorre apenas durante o cálculo; a variável i mantém sempre o seu tipo int.
2.4. Instruções de controlo de fluxo do programa
2.4.1. Pare
O método exit definido na classe System permite-lhe interromper a execução de um programa.
Ação: interrompe o processo atual e devolve o valor do estado ao processo pai
exit encerra o processo atual e devolve o controlo ao processo de chamada. O valor de estado pode ser utilizado pelo processo de chamada. No DOS, esta variável de estado é devolvida ao DOS na variável de sistema ERRORLEVEL, cujo valor pode ser verificado num ficheiro batch. No Unix, a variável $? recupera o valor de estado se o interpretador de comandos for o Bourne Shell (/bin/sh).
Exemplo:
para encerrar o programa com um valor de estado de 0.
2.4.2. Estrutura condicional simples
syntaxe : if (condition) {actions_condition_vraie;} else {actions_condition_fausse;}
notas:
- A condição é colocada entre parênteses.
- Cada ação é terminada por um ponto e vírgula.
- As chaves não são seguidas de ponto e vírgula.
- As chaves só são necessárias se houver mais do que uma ação.
- A cláusula else pode ser omitida.
- Não existe «then».
O equivalente algorítmico desta estrutura é a estrutura if-then-else:
exemplo
if (x>0) { nx=nx+1;sx=sx+x;} else dx=dx-x;
É possível aninhar estruturas de decisão:
Por 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 que instrução if se refere o else? A regra é que um else se refere sempre à instrução *if mais próxima: if(n>6)* neste exemplo. Vejamos outro exemplo:
public static void main(void)
{ int n=0;
if(n>1)
if(n>6) System.out.println(">6");
else; // else from if(n>6): nothing to do
else System.out.println("<=1"); // else du if(n>1)
}
Aqui, queríamos colocar um else na instrução if(n>1) e nenhum else na instrução if(n>6). Devido à nota anterior, somos obrigados a colocar um else na instrução if(n>6), na qual não há nenhuma instrução.
2.4.3. Estrutura de caso
A sintaxe é a seguinte:
switch(expression) {
case v1:
actions1;
break;
case v2:
actions2;
break;
. .. .. .. .. ..
default: actions_sinon;
}
notas
- O valor da expressão de controlo só pode ser um número inteiro ou um caractere.
- A expressão de controlo é colocada entre parênteses.
- A cláusula padrão pode ser omitida.
- Os valores vi são valores possíveis da expressão. Se a expressão for avaliada como vi, as ações que se seguem à cláusula case vi são executadas.
- A instrução break sai da estrutura case. Se estiver ausente no final do bloco de instruções para o valor vi, a execução continua com as instruções para o 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 loop
2.4.4.1. Número conhecido de repetições
Sintaxe
for (i=id;i<=if;i=i+ip){
actions;
}
Notas
- Os três argumentos do ciclo for estão entre parênteses.
- Os três argumentos do ciclo for são separados por ponto e vírgula.
- Cada ação no ciclo for é terminada por um ponto e vírgula.
- A chave só é necessária se houver mais do que uma ação.
- A chave não é seguida de ponto e vírgula.
O equivalente algorítmico é a estrutura «for»:
o que pode ser traduzido numa estrutura while:
2.4.4.2. Número de repetições desconhecido
Existem muitas estruturas de controlo em Java para este caso.
Loop while
while(condition){
actions;
}
O ciclo continua enquanto a condição for verdadeira. O ciclo pode nunca ser executado.
Notas:
- A condição está entre parênteses.
- Cada ação é terminada por um ponto e vírgula.
- As chaves só são necessárias se houver mais do que uma ação.
- A chave não é seguida de ponto e vírgula.
A estrutura algorítmica correspondente é a estrutura while:
Estrutura do-while
A sintaxe é a seguinte:
do{
instructions;
}while(condition);
O ciclo continua até que a condição se torne falsa ou enquanto a condição for verdadeira. Aqui, o ciclo é executado pelo menos uma vez.
Notas
- A condição está entre parênteses.
- Cada ação é terminada por um ponto e vírgula.
- As chaves só são necessárias se houver mais do que uma ação.
- A chave não é seguida de ponto e vírgula.
A estrutura algorítmica correspondente é a estrutura «repeat ... until»:
Estrutura para o geral (para)
A sintaxe é a seguinte:
for(instructions_départ;condition;instructions_fin_boucle){
instructions;
}
O ciclo continua enquanto a condição for verdadeira (avaliada antes de cada iteração). As instruções_iniciais são executadas antes de entrar no ciclo pela primeira vez. As instruções_finais_do_ciclo são executadas após cada iteração.
Notas
- Os três argumentos do ciclo for são colocados entre parênteses.
- Os três argumentos do ciclo for são separados por ponto e vírgula.
- Cada instrução for é terminada por um ponto e vírgula.
- A chave só é necessária se houver mais do que uma ação.
- A chave não é seguida de um ponto e vírgula.
- As várias instruções em start_statements e end_loop_statements são separadas por vírgulas.
A estrutura algorítmica correspondente é a seguinte:
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 de controlo de loop
break | Sai do ciclo for, while ou do...while. |
continue | avança para a próxima iteração dos loops for, while e do...while |
2.5. A estrutura de um programa Java
Um programa Java que não utilize classes ou funções definidas pelo utilizador, além da função main, pode ter a seguinte estrutura:
public class test1{
public static void main(String arg[]){
… code du programme
}// hand
}// class
A função main, também conhecida como método, é a primeira a ser executada ao executar um programa Java. Deve ter a seguinte assinatura:
public static void main(String arg[]){
ou
public static void main(String[] arg){
O nome do argumento arg pode ser qualquer coisa. Trata-se de uma matriz de cadeias de caracteres que representa os argumentos da linha de comandos. Voltaremos a este assunto mais tarde.
Se utilizar funções que possam lançar exceções que não deseja tratar explicitamente, pode envolver o código do programa num bloco try/catch:
public class test1{
public static void main(String arg[]){
try{
… code du programme
} catch (Exception e){
// error handling
}// try
}// hand
}// class
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
}// hand
}// class
Vamos ver um exemplo. Considere a seguinte instrução de escrita:
que imprime "java" no ecrã. Há muita coisa a acontecer nesta instrução simples:
- System é uma classe cujo nome completo é java.lang.System
- out é uma propriedade desta classe do tipo java.io.PrintStream, outra classe
- println é um método da classe java.io.PrintStream.
Não vamos complicar desnecessariamente esta explicação, que surge demasiado cedo, uma vez que requer uma compreensão do conceito de classe que ainda não foi abordado. Uma classe pode ser considerada como um recurso. Aqui, o compilador precisará de aceder às classes java.lang.System e java.io.PrintStream. As centenas de classes Java estão organizadas em arquivos também conhecidos como pacotes. As instruções import colocadas no início do programa são usadas para indicar ao compilador quais classes externas o programa necessita (aquelas usadas, mas não definidas no ficheiro fonte a ser compilado). Assim, no nosso exemplo, o nosso programa necessita das classes java.lang.System e java.io.PrintStream. Especificamos isso com a instrução import. Poderíamos escrever no início do programa:
Uma vez que um programa Java utiliza normalmente dezenas de classes externas, seria tedioso escrever todas as instruções de importação necessárias. As classes foram agrupadas em pacotes, e podemos importar o pacote na totalidade. Assim, para importar os pacotes java.lang e java.io, escrevemos:
O pacote java.lang contém todas as classes base do Java e é importado automaticamente pelo compilador. Por isso, em última análise, basta escrever:
2.6. Tratamento de exceções
Muitas funções Java são capazes de gerar exceções, ou seja, erros. Já nos deparámos com 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 é suscetível de lançar uma exceção, o compilador Java exige que o programador a trate, a fim de produzir programas mais resistentes a erros: deve evitar sempre que uma aplicação «trave» inesperadamente. Aqui, a função readLine lança uma exceção se não houver nada para ler — por exemplo, porque o fluxo de entrada foi fechado. O tratamento de exceções segue este padrão:
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 lançar uma exceção, o programa passa para a instrução seguinte; caso contrário, entra no corpo da cláusula catch e, em seguida, passa para a instrução seguinte. Tenha em atenção os seguintes pontos:
- e é um objeto derivado do tipo Exception. Podemos ser mais específicos utilizando tipos como IOException, SecurityException, ArithmeticException, etc.: existem cerca de vinte tipos de exceções. Ao escrever catch (Exception e), indicamos que queremos tratar todos os tipos de exceções. Se for provável que o código no bloco try gere vários tipos de exceções, talvez seja melhor sermos mais específicos, tratando a exceção com vários blocos 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
- Pode ser adicionada uma cláusula finally aos blocos 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, quer ocorra ou não uma exceção, o código na cláusula finally será sempre executado.
- A classe Exception possui um método getMessage() que retorna uma mensagem detalhando o erro que ocorreu. Portanto, se quisermos exibir essa mensagem, escrevemos:
catch (Exception ex){
System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
...
}//catch
- A classe Exception possui um método toString() que devolve uma cadeia de caracteres indicando o tipo de exceção e o valor da propriedade Message. Podemos, portanto, escrever:
catch (Exception ex){
System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
...
}//catch
Também podemos escrever:
Aqui temos uma operação string + Exception que será automaticamente convertida em string + Exception.toString() pelo compilador, a fim de concatenar duas strings.
O exemplo seguinte mostra uma exceção gerada pela utilização de um elemento de matriz inexistente:
// tables
// imports
import java.io.*;
public class tab1{
public static void main(String[] args){
// declaring & initializing an array
int[] tab=new int[] {0,1,2,3};
int i;
// table display with for
for (i=0; i<tab.length; i++)
System.out.println("tab[" + i + "]=" + tab[i]);
// generating an exception
try{
tab[100]=6;
}catch (Exception e){
System.err.println("L'erreur suivante s'est produite : " + e);
}//try-catch
}//hand
}//class
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 tratamos a exceção causada pela atribuição de uma string a um número quando a string não representa um número:
// imports
import java.io.*;
public class console1{
public static void main(String[] args){
// creation of an input stream
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
}catch(Exception ex){}
// We ask for the name
System.out.print("Nom : ");
// reading response
String nom=null;
try{
nom=IN.readLine();
}catch(Exception ex){}
// age requested
int age=0;
boolean ageOK=false;
while ( ! ageOK){
// question
System.out.print("âge : ");
// read-verify answer
try{
age=Integer.parseInt(IN.readLine());
ageOK=true;
}catch(Exception ex) {
System.err.println("Age incorrect, recommencez...");
}//try-catch
}//while
// final display
System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
}//Main
}//class
Alguns resultados da execução:
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. Compilar e executar um programa Java
Compile e, em seguida, execute o seguinte programa:
// importing classes
import java.io.*;
// test class
public class coucou{
// hand function
public static void main(String args[]){
// screen display
System.out.println("coucou");
}//hand
}//class
O ficheiro fonte que contém a classe coucou anterior deve ser denominado coucou.java:
A compilação e a execução de um programa Java são feitas numa janela do 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 irá analisar o ficheiro fonte .java e produzir um ficheiro .class compilado. Este ficheiro não é imediatamente executável pelo processador. Requer um interpretador Java (java.exe), conhecido como máquina virtual ou JVM (Java Virtual Machine). A partir do código intermédio no ficheiro .class, a máquina virtual gera instruções específicas para o processador da máquina na qual está a ser executada. Existem máquinas virtuais Java para diferentes tipos de sistemas operativos (Windows, Unix, Mac OS, etc.). Um ficheiro .class pode ser executado por qualquer uma destas máquinas virtuais e, portanto, em qualquer sistema operativo. Esta portabilidade entre sistemas é um dos principais pontos fortes 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 ficheiro .class gerado:
Note que no comando de execução acima, não especificámos a extensão .class para o ficheiro coucou.class a ser executado. Ela está implícita. Se o diretório bin do JDK estiver no PATH da máquina DOS, não precisamos de fornecer o caminho completo para os executáveis javac.exe e java.exe. Podemos simplesmente escrever
2.8. Principais argumentos do programa
A função principal aceita uma matriz de cadeias de caracteres como parâmetros: String[]. Esta matriz contém os argumentos da linha de comandos utilizados para iniciar a aplicação. Assim, se iniciarmos o programa P com o comando:
e se a função principal for declarada da seguinte forma:
teremos arg[0]="arg0", arg[1]="arg1" … Aqui está 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 são os seguintes:
2.9. Passar parâmetros para uma função
Os exemplos anteriores mostraram apenas programas Java com uma única função, a função main. O exemplo seguinte demonstra como utilizar funções e como a informação é trocada entre elas. Os parâmetros de função são sempre passados por valor: ou seja, o valor do parâmetro real é 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:
Os valores dos parâmetros efetivos «pai» e 20 foram copiados para os parâmetros formais S e a. Estes foram então modificados. Os parâmetros efetivos permaneceram inalterados. Note-se aqui o tipo dos parâmetros efetivos:
- S é uma referência a um objeto, ou seja, o endereço de um objeto na memória
- age é um inteiro
2.10. Um exemplo de cálculo de impostos
Concluiremos este capítulo com um exemplo que iremos revisitar várias vezes neste documento. Propomos escrever um programa para calcular o imposto de um contribuinte. Consideramos o caso simplificado de um contribuinte que tem apenas o seu salário para declarar:
- calculamos o número de escalões de imposto para o trabalhador como nbParts = nbEnfants / 2 + 1 se for solteiro, e nbEnfants / 2 + 2 se for casado, sendo que nbEnfants é o número de filhos.
- Se tiver pelo menos três filhos, recebe uma meia quota adicional.
- Calculamos o rendimento tributável R = 0,72 × S, em que S é o salário anual
- Calculamos o coeficiente familiar QF = R / nbParts
- Calculamos o seu imposto I. Considere a seguinte tabela:
12 620,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 tem 3 campos. Para calcular o imposto I, procuramos a primeira linha em que QF <= campo1. Por exemplo, se QF = 23.000, encontraremos a linha
O Imposto I é então igual a 0,15*R - 2072,5*nbParts. Se QF for tal que a condição QF<=field1 nunca seja satisfeita, então são utilizados os coeficientes da última linha. Aqui:
o que dá o imposto I = 0,65*R - 49062*nbParts.
O programa Java correspondente é o seguinte:
import java.io.*;
public class impots{
// ------------ hand
public static void main(String arg[]){
// data
// tax bracket limits
double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};
// coefficient applied to the number of shares
double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};
// the program
// keyboard input stream creation
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
}
catch(Exception e){
erreur("Création du flux d'entrée", e, 1);
}
// we recover marital status
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");
// number of children
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
// salary
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
}// while
// calculating the number of shares
double NbParts;
if(Marie) NbParts=(double)NbEnfants/2+2;
else NbParts=(double)NbEnfants/2+1;
if (NbEnfants>=3) NbParts+=0.5;
// taxable income
double Revenu;
Revenu=0.72*Salaire;
// family quotient
double QF;
QF=Revenu/NbParts;
// search for tax bracket corresponding to QF
int i;
int NbTranches=Limites.length;
Limites[NbTranches-1]=QF;
i=0;
while(QF>Limites[i]) i++;
// tax
long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);
// the result is displayed
System.out.println("Impôt à payer : " + impots);
}// hand
// ------------ error
private static void erreur(String msg, Exception e, int exitCode){
System.err.println(msg+"("+e+")");
System.exit(exitCode);
}// error
}// class
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