Skip to content

2. Fundamentos del lenguaje Java

2.1. Introducción

En primer lugar, trataremos Java como un lenguaje de programación clásico. Abordaremos los objetos más adelante.

En un programa hay dos tipos de elementos

  • datos
  • las instrucciones que los manipulan

Por lo general, se intenta separar los datos de las instrucciones:

Image

2.2. Los datos en Java

Java utiliza los siguientes tipos de datos:

  • los números enteros
  • los números reales
  • caracteres y cadenas de caracteres
  • los booleanos
  • los objetos

2.2.1. Los tipos de datos predefinidos

Tipo
Codificación
Dominio
char
2 bytes
carácter 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] en valor absoluto
double
8 bytes
[1.7 10-308 , 1.7 10+308] en valor absoluto
boolean
1 bit
verdadero, falso
String
referencia de objeto
cadena de caracteres
Date
referencia de objeto
fecha
Character
Referencia del objeto
char
Integer
Referencia de objeto
int
Long
referencia de objeto
long
Byte
Referencia de objeto
byte
Float
referencia de objeto
flotante
Double
referencia de objeto
double
Boolean
referencia de objeto
booleano

2.2.2. Notación de datos literales

entier
145, -7, 0xFF (hexadecimal)
real doble
134,789; -45E-18 (-45 × 10⁻¹⁸)
flotante
134.789F, -45E-18F (-45 × 10⁻¹⁸)
caractère
'A', 'b'
cadena de caracteres
«hoy»
booléen
verdadero, falso
date
new Date(13,10,1954) (día, mes, año)

2.2.3. Declaración de datos

2.2.3.1. Función de las declaraciones

Un programa maneja datos caracterizados por un nombre y un tipo. Estos datos se almacenan en memoria. En el momento de la compilación del programa, el compilador asigna a cada dato una ubicación en memoria caracterizada por una dirección y un tamaño. Lo hace basándose en las declaraciones realizadas por el programador.

Además, estas permiten al compilador detectar errores de programación. Así, la operación

x = x * 2;

se considerará errónea si x es, por ejemplo, una cadena de caracteres.

2.2.3.2. Declaración de constantes

La sintaxis para declarar una constante es la siguiente:

final tipo nombre=valor; //define la constante nombre=valor

ej.: final float PI=3.141592F;

Nota

¿Por qué declarar constantes?

  • La lectura del programa resultará más sencilla si se le da a la constante un nombre significativo:

ej.: final float taux_tva = 0.186F;

  • Modificar el programa resultará más sencillo si la «constante» llega a cambiar. Así, en el caso anterior, si el tipo del IVA pasa al 33 %, la única modificación que habrá que realizar será cambiar la instrucción que define su valor:

final float taux_tva=0.33F;

Si se hubiera utilizado 0,186 explícitamente en el programa, habría que modificar numerosas instrucciones.

2.2.3.3. Declaración de variables

Una variable se identifica mediante un nombre y se asocia a un tipo de datos. El nombre de una variable en Java tiene n caracteres: el primero debe ser una letra, y los demás pueden ser letras o números. Java distingue entre mayúsculas y minúsculas. Por lo tanto, las variables FIN y fin son diferentes.

Las variables pueden inicializarse en el momento de su declaración. La sintaxis para declarar una o varias variables es:

identificateur_de_type variable1,variable2,...,variablen;

donde identificateur_de_type es un tipo predefinido o un tipo de objeto definido por el programador.

2.2.4. Las conversiones entre números y cadenas de caracteres

número -> cadena
"" + número
cadena -> int
Integer.parseInt(cadena)
cadena -> entero largo
Long.parseLong(cadena)
cadena -> doble
Double.valueOf(cadena).doubleValue()
cadena -> float
Float.valueOf(cadena).floatValue()

A continuación se muestra un programa que presenta las principales técnicas de conversión entre números y cadenas de caracteres. La conversión de una cadena a un número puede fallar si la cadena no representa un número válido. En ese caso, se genera un error fatal denominado «excepción» en Java. Este error puede gestionarse mediante la siguiente cláusula try/catch:

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

Si la función no genera ninguna excepción, se pasa a la siguiente instrucción; en caso contrario, se pasa al cuerpo de la cláusula catch y, a continuación, a la siguiente instrucción. Más adelante volveremos sobre la gestión de excepciones.


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 --> cadena
    S=""+i;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);

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

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

    // cadena --> entero largo
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // cadena --> doble
    double d1;
    d1=Double.valueOf("100.87").doubleValue();
    affiche(""+d1);
    try{
      d1=Double.valueOf("abcd").doubleValue();
      affiche(""+d1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }

    // cadena --> 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);
    }

}// fin main

  public static void affiche(String S){
    System.out.println("S="+S);
  }
}// fin de clase

Los resultados obtenidos son los siguientes:

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. Las tablas de datos

Una matriz en Java es un objeto que permite agrupar datos del mismo tipo bajo un mismo identificador. Su declaración es la siguiente:

Tipo Matriz[] = new Tipo[n] o Tipo[] Matriz = new Tipo[n]

Ambas sintaxis son válidas. n es el número de datos que puede contener el array. La sintaxis Array[i] hace referencia al dato n.º i, donde i pertenece al intervalo [0,n-1]. Cualquier referencia al dato Tableau[i] en la que i no pertenezca al intervalo [0,n-1] provocará una excepción.

Una matriz bidimensional se puede declarar de la siguiente manera:

Tipo Matriz[][] = new Tipo[n][p] o Tipo[][] Matriz = new Tipo[n][p]

La sintaxis «Tabla[i]» hace referencia al dato n.º i de Tableau, donde i pertenece al intervalo [0,n-1]. Tableau[i] es a su vez una tabla: Tableau[i][j] hace referencia al dato n.º j de la tabla [i], donde j pertenece al intervalo [0,p-1]. Cualquier referencia a un dato de Tableau con índices incorrectos genera un error fatal.

He aquí un ejemplo:


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]);
  }
}

y los resultados de la ejecución:

2
0.33

Una matriz es un objeto que posee el atributo length: es el tamaño de la matriz.

2.3. Las instrucciones básicas de Java

Se distingue

  • las instrucciones elementales ejecutadas por el ordenador
  • las instrucciones de control del desarrollo del programa.

Las instrucciones elementales se aprecian claramente al analizar la estructura de un microordenador y sus periféricos.

Image

  1. Lectura de información procedente del teclado

  2. Procesamiento de información

  3. Escritura de información en la pantalla

  4. Lectura de información procedente de un archivo en disco

  5. Escritura de información en un archivo del disco

2.3.1. Escritura en pantalla

La sintaxis de la instrucción de escritura en pantalla es la siguiente:

System.out.println(expresión) o System.err.println(expresión)

donde expression es cualquier tipo de dato que pueda convertirse en una cadena de caracteres para mostrarse en pantalla. En el ejemplo anterior, hemos visto dos instrucciones de escritura:

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

System.out escribe en un archivo de texto que, por defecto, es la pantalla. Lo mismo ocurre con System.err. Estos archivos llevan un número (o descripteur) de 1 y 2, respectivamente. El flujo de entrada del teclado (System.in) también se considera un archivo de texto, con el descriptor 0. Tanto DOS como Unix admiten el uso de tuberías (pipe) entre comandos:

    commande1 | commande2

Todo lo que commande1 escribe con System.out se redirige a la entrada System.in de commande2. Dicho de otro modo, commande2 lee, mediante System.in, los datos generados por commande2 con System.out, que, por lo tanto, ya no se muestran en pantalla. Este sistema se utiliza mucho en Unix. En esta encadenación, el flujo System.err no se redirige: escribe en la pantalla. Por eso se utiliza para escribir los mensajes de error (de ahí su nombre, err): así se garantiza que, durante un redireccionamiento de comandos, los mensajes de error seguirán mostrándose en pantalla. Por lo tanto, se acostumbra a escribir los mensajes de error en pantalla con el flujo System.err en lugar de con el flujo System.out.

2.3.2. Lectura de datos introducidos mediante el teclado

El flujo de datos procedente del teclado viene designado por el objeto System.in, de tipo InputStream. Este tipo de objetos permite leer datos carácter por carácter. Corresponde al programador extraer posteriormente de este flujo de caracteres la información que le interese. El tipo InputStream no permite leer una línea de texto de una sola vez. El tipo BufferedReader sí lo permite mediante el método readLine.

Para poder leer líneas de texto introducidas mediante el teclado, a partir del flujo de entrada System.in de tipo InputStream, se crea otro flujo de entrada, esta vez de tipo BufferedReader:

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

No explicaremos aquí los detalles de esta instrucción, que implica el concepto de construcción de objetos. La utilizaremos tal cual.

La creación de un flujo puede fallar: en ese caso, se genera un error fatal, denominado «excepción» en Java. Cada vez que un método puede generar una excepción, el compilador de Java exige que el programador la gestione. Por lo tanto, para crear el flujo de entrada anterior, habrá que escribir en realidad:


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

Una vez más, no vamos a explicar aquí la gestión de excepciones. Una vez creado el flujo IN anterior, se puede leer una línea de texto mediante la instrucción:

    String ligne;
    ligne=IN.readLine();

La línea introducida con el teclado se almacena en la variable ligne y, a continuación, el programa puede utilizarla.

2.3.3. Ejemplo de entradas y salidas

A continuación se muestra un programa que ilustra las operaciones de entrada y salida del teclado y la pantalla:


import java.io.*;        // necesario para el uso de flujos de E/S

public class io1{
  
  
  public static void main (String[] arg){
    
    // escritura en el flujo System.out
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // escritura en el flujo System.err
    int i=10;
    System.err.println("i="+i);
    
    // lectura de una línea introducida mediante el 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);
    }
  }//fin de la entrada manual

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

}//fin de clase

y los resultados de la ejecución:

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à

Las instrucciones

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

tienen como objetivo mostrar que cualquier objeto puede ser objeto de una visualización. Aquí no vamos a explicar el significado de lo que se muestra. También tenemos la visualización del valor de un objeto en el bloque:

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

La variable e es un objeto de tipo Exception que se muestra aquí con la llamada affiche(e). Ya nos habíamos encontrado, sin mencionarlo, con esta visualización del valor de una excepción en el programa de conversión visto anteriormente.

2.3.4. Asignación del valor de una expresión a una variable

Aquí nos centramos en la operación variable=expression;

La expresión puede ser de tipo: aritmético, relacional, booleano o de caracteres

2.3.4.1. Interpretación de la operación de asignación

La operación variable=expression; es en sí misma una expresión cuya evaluación se lleva a cabo de la siguiente manera:

  • Se evalúa el lado derecho de la asignación: el resultado es un valor V.
  • El valor V se asigna a la variable
  • el valor V es también el valor de la asignación, considerada esta vez como una expresión.

Por eso, la operación V1=V2=expresión es válida. Debido a la prioridad, se evaluará el operador = situado más a la derecha. Por lo tanto, tenemos V1=(V2=expresión). La expresión V2=expresión se evalúa y tiene como valor V. La evaluación de esta expresión ha provocado la asignación de V a V2. A continuación, se evalúa el siguiente operador = de la forma V1=V. El valor de esta expresión sigue siendo V. Su evaluación provoca la asignación de V a V1. Por lo tanto, la operación V1=V2=expresión es una expresión cuya evaluación

1: provoca la asignación del valor de expression a las variables V1 y V2

2: devuelve como resultado el valor de expression.

Se puede generalizar a una expresión del tipo: V1=V2=....=Vn=expresión

2.3.4.2. Expresión aritmética

Los operadores de las expresiones aritméticas son los siguientes:

+: suma

-: resta

*: multiplicación

/: división: el resultado es el cociente exacto si al menos uno de los operandos es un número real. Si ambos operandos son enteros, el resultado es el cociente entero. Así, 5/2 → 2 y 5,0/2 → 2,5.

%: división: el resultado es el resto, independientemente de la naturaleza de los operandos, siendo el cociente un número entero. Se trata, por tanto, de la operación módulo.

Existen diversas funciones matemáticas:

double sqrt(double x)
raíz cuadrada
double cos(double x)
coseno
double sin(double x)
seno
doble tan(doble 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 estas funciones están definidas en una clase de Java llamada Math. Al utilizarlas, hay que anteponerles el nombre de la clase en la que están definidas. Así, se escribirá:

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

La definición de la clase Math es la siguiente:


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 en la evaluación de expresiones aritméticas

El orden de prioridad de los operadores al evaluar una expresión aritmética es el siguiente (de mayor a menor prioridad):

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

Los operadores de un mismo bloque [ ] tienen la misma prioridad.

2.3.4.4. Expresiones relacionales

Los operadores son los siguientes: <, <=, ==, !=, >, >=

orden de prioridad

>, >=, <, <=

==, !=

El resultado de una expresión relacional es el valor booleano false si la expresión es falsa, y true en caso contrario.

Ejemplo:

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

Comparación de dos caracteres

Supongamos que tenemos dos caracteres: C1 y C2. Es posible compararlos con los operadores

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

En este caso, lo que se comparan son sus códigos ASCII, que son números. Recordemos que, según el orden ASCII, se dan las siguientes relaciones:

espacio < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. < 'z'

Comparación de dos cadenas de caracteres

Se comparan carácter por carácter. La primera desigualdad que se encuentra entre dos caracteres da lugar a una desigualdad del mismo sentido en las cadenas.

Ejemplos:

Supongamos que queremos comparar las cadenas «Gato» y «Perro»

Esta última desigualdad permite afirmar que «Gato» < «Perro».

Image

Supongamos que queremos comparar las cadenas «Gato» y «Gatito». Hay igualdad en todo momento hasta que se agota la cadena «Gato». En este caso, la cadena agotada se declara como la más «pequeña». Por lo tanto, tenemos la relación

«Gato» < «Gatito».

Funciones de comparación de dos cadenas

Aquí no se pueden utilizar los operadores relacionales <, <=, ==, !=, >, >=. Hay que utilizar métodos de la clase String:

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

En el ejemplo anterior, la variable i tendrá el valor:

0: si ambas cadenas son iguales

1: si la cadena n.º 1 es mayor que la cadena n.º 2

-1: si la cadena n.º 1 es menor que la cadena n.º 2

La variable egal tendrá el valor true si ambas cadenas son iguales.

2.3.4.5. Expresiones booleanas

Los operadores son & (and) ||(or) y ! (not). El resultado de una expresión booleana es un valor booleano.

orden de prioridad !, &&, ||

ejemplo:

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

Los operadores relacionales tienen prioridad sobre los operadores && y ||.

2.3.4.6. Operaciones con bits

Los operadores

Sean i y j dos números enteros.

i<<n
desplaza i n bits hacia la izquierda. Los bits entrantes son ceros.
i>>n
desplaza i n bits a la derecha. Si i es un entero con signo (signed char, int, long), se conserva el bit de signo.
i & j
realiza la operación lógica ET de i y j bit a bit.
i | j
realiza la operación lógica OU de i y j bit a bit.
~i
complementa i a 1
i^j
realiza la operación OU EXCLUSIF con i y j

Sea

    int i=0x123F, k=0xF123;
    unsigned j=0xF123;
operación
valor
i<<4
0x23F0
i>>4
0x0123 se conserva el bit de signo.
k>>4
0xFF12 se conserva el bit de signo.
i&j
0x1023
i|j
0xF33F
~i
0xEDC0

2.3.4.7. Combinación de operadores

a=a+b se puede escribir como a+=b

a=a-b se puede escribir como a-=b

Lo mismo ocurre con los operadores /, %, *, <<, >>, &, |, ^

Así, a=a+2; se puede escribir como a+=2;

2.3.4.8. Operadores de incremento y decremento

La notación variable++ significa variable=variable+1 o también variable+=1

La notación variable-- significa variable=variable-1 o también variable-=1.

2.3.4.9. ¿El operador?

La expresión expr_cond ? expr1:expr2 se evalúa de la siguiente manera:

1: se evalúa la expresión expr_cond. Se trata de una expresión condicional cuyo valor es verdadero o falso

2: si es verdadera, el valor de la expresión es el de expr1. expr2 no se evalúa.

3: Si es falsa, ocurre lo contrario: el valor de la expresión es el de expr2. expr1 no se evalúa.

Ejemplo

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

asignará a la variable i:

j+1 si j>4; j-1 en caso contrario

Es lo mismo que escribir if(j>4) i=j+1; else i=j-1; pero es más conciso.

2.3.4.10. Prioridad general de los operadores

() [] función
gd
! ~ ++ --
dg
new (tipo) operadores de conversión
dg
* / %
gd
+ -
gd
<< >>
gd
< <= > >= instanceof
gd
== !=
gd
&
gd
^
gd
|
gd
&&
gd
||
gd
? :
dg
= += -= etc. .
dg

gd: indica que, en caso de igualdad de prioridad, se aplica la prioridad de izquierda a derecha. Esto significa que, cuando en una expresión hay operadores con la misma prioridad, se evalúa primero el operador situado más a la izquierda en la expresión. dg indica una prioridad de derecha a izquierda.

2.3.4.11. Los cambios de tipo

En una expresión, es posible cambiar momentáneamente la codificación de un valor. A esto se le denomina «cambio de tipo» o, en inglés, «type casting». La sintaxis para cambiar el tipo de un valor en una expresión es la siguiente: (tipo) valor. El valor adopta entonces el tipo indicado. Esto conlleva un cambio en la codificación del valor.

Ejemplo:

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

En este caso, es necesario cambiar el tipo de i o j a real; de lo contrario, la división dará como resultado un cociente entero y no real.

i es un valor codificado de forma exacta en 2 bytes

(float) i es el mismo valor codificado de forma aproximada como número real en 4 bytes

Por lo tanto, se produce una transcodificación del valor de i. Esta transcodificación solo tiene lugar durante el tiempo que dura un cálculo, ya que la variable i conserva siempre su tipo int.

2.4. Las instrucciones para supervisar el desarrollo del programa

2.4.1. Detener

El método exit, definido en la clase System, permite detener la ejecución de un programa.

Sintaxis : void exit(int status)

Acción: detiene el proceso en curso y devuelve el valor status al proceso padre

exit provoca la finalización del proceso en curso y devuelve el control al proceso que lo ha llamado. Este último puede utilizar el valor de status. En DOS, esta variable status se devuelve a DOS en la variable del sistema ERRORLEVEL, cuyo valor puede comprobarse en un archivo por lotes. En Unix, es la variable $? la que recoge el valor de status si el intérprete de comandos es el Bourne Shell (/bin/sh).

Ejemplo:

    System.exit(0);

para detener el programa con un valor de estado igual a 0.

2.4.2. Estructura de selección simple


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

Notas:

  • la condición va entre paréntesis.
  • Cada acción termina con un punto y coma.
  • Las llaves no terminan con punto y coma.
  • Las llaves solo son necesarias si hay más de una acción.
  • La cláusula «else» puede omitirse.
  • No hay «then».

El equivalente algorítmico de esta estructura es la estructura «si... entonces... si no»:

si condition
  alors actions_condition_vraie
  sinon actions_conditions_fausse
finsi

ejemplo


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

Las estructuras de selección se pueden anidar:

if(condition1)
if (condition2)
        {......}
      else         //condición2
         {......}
else         //condición1
     {.......}

A veces surge el siguiente problema:


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

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

En el ejemplo anterior, ¿a qué if se refiere el else? La regla es que un else siempre se refiere al if más cercano: if(n>6) en el ejemplo. Veamos otro ejemplo:


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

   if(n>1)
     if(n>6)   System.out.println(">6");
     else;            // else del if(n>6): nada que hacer 
   else System.out.println("<=1");    // else del if(n>1) 
}

Aquí queríamos poner un else en el if(n>1) y no un else en el if(n>6). Debido a la observación anterior, nos vemos obligados a incluir un «else» para el if(n>6), en el que no hay ninguna instrucción.

2.4.3. Estructura de casos

La sintaxis es la siguiente:

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

Notas

  • El valor de la expresión de control solo puede ser un número entero o un carácter.
  • La expresión de control va entre paréntesis.
  • La cláusula default puede omitirse.
  • Los valores vi son valores posibles de la expresión. Si la expresión tiene como valor vi, se ejecutan las acciones que siguen a la cláusula «case» vi.
  • La instrucción break sale de la estructura «case». Si no aparece al final del bloque de instrucciones del valor vi, la ejecución continúa con las instrucciones del valor vi+1.

Ejemplo

En 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

En 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. Estructura de repetición

2.4.4.1. Número de repeticiones conocido

Sintaxis


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

Notas

  • Los tres argumentos de for van entre paréntesis.
  • Los tres argumentos de for están separados por punto y coma.
  • Cada acción de for termina con un punto y coma.
  • Las llaves solo son necesarias si hay más de una acción.
  • La llave no va seguida de un punto y coma.

El equivalente algorítmico es la estructura pour:

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

que se puede traducir a una estructura tantque:

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

2.4.4.2. Número de repeticiones desconocido

En Java existen numerosas estructuras para este caso.

Estructura «while»


    while(condition){
          actions;
        } 

El bucle se repite mientras se cumpla la condición. Es posible que el bucle nunca se ejecute.

Notas:

  • La condición va entre paréntesis.
  • Cada acción termina con un punto y coma.
  • Las llaves solo son necesarias si hay más de una acción.
  • La llave no va seguida de punto y coma.

La estructura algorítmica correspondiente es la estructura «while»:

tantque condition
        actions
fintantque

Estructura «repetir hasta» (do while)

La sintaxis es la siguiente:


    do{
       instructions;
    }while(condition); 

El bucle se repite hasta que la condición se vuelva falsa o mientras la condición sea verdadera. En este caso, el bucle se ejecuta al menos una vez.

Notas

  • La condición va entre paréntesis.
  • Cada acción termina con un punto y coma.
  • Las llaves solo son necesarias si hay más de una acción.
  • La llave no va seguida de punto y coma.

La estructura algorítmica correspondiente es la estructura «repetir… hasta»:

répéter
    actions
jusqu'à condition

Estructura «for» (for)

La sintaxis es la siguiente:


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

El bucle se repite mientras la condición sea verdadera (se evalúa antes de cada iteración). Las instrucciones Instructions_départ se ejecutan antes de entrar en el bucle por primera vez. Las instrucciones Instructions_fin_boucle se ejecutan después de cada iteración.

Notas

  • Los tres argumentos de for van entre paréntesis.
  • Los tres argumentos de for están separados por punto y coma.
  • Cada acción del «for» termina con un punto y coma.
  • La llave solo es necesaria si hay más de una acción.
  • La llave no va seguida de un punto y coma.
  • Las diferentes instrucciones de instructions_depart y instructions_fin_boucle están separadas por comas.

La estructura algorítmica correspondiente es la siguiente:

instructions_départ
tantque condition
        actions
        instructions_fin_boucle
fintantque

Ejemplos

Los siguientes programas calculan la suma de los primeros n números enteros.


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);

Instrucciones para la gestión de bucles

break
sale del bucle «for», «while» o «do...while».
continue
pasa a la siguiente iteración de los bucles «for», «while» y «do...while»

2.5. La estructura de un programa Java

Un programa Java que no utilice clases definidas por el usuario ni funciones distintas de la función principal main puede tener la siguiente estructura:


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

La función main, también denominada método, es la primera que se ejecuta al ejecutar un programa Java. Debe tener obligatoriamente la siguiente firma:


    public static void main(String arg[]){

o


    public static void main(String[] arg){

El nombre del argumento arg puede ser cualquiera. Se trata de una matriz de cadenas de caracteres que representan los argumentos de la línea de comandos. Volveremos sobre esto más adelante.

Si se utilizan funciones que puedan generar excepciones que no se desee gestionar en detalle, se puede enmarcar el código del programa con una cláusula try/catch:


public class test1{
    public static void main(String arg[]){
        try{
        … code du programme
        } catch (Exception e){
            // gestión de errores
        }// try
    }// main
}// clase

Al principio del código fuente y antes de la definición de la clase, es habitual encontrar instrucciones de importación de clases. Por ejemplo:


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

Veamos un ejemplo. Supongamos que tenemos la siguiente instrucción de escritura:

System.out.println("java");

que escribe java en la pantalla. En esta sencilla instrucción hay muchas cosas:

  • System es una clase cuyo nombre completo es java.lang.System
  • out es una propiedad de esta clase de tipo java.io.PrintStream, otra clase
  • println es un método de la clase java.io.PrintStream.

No complicaremos innecesariamente esta explicación, que llega demasiado pronto, ya que requiere comprender el concepto de «clase», que aún no se ha abordado. Se puede equiparar una clase a un recurso. En este caso, el compilador necesitará tener acceso a las dos clases java.lang.System y java.io.PrintStream. Los cientos de clases de Java se distribuyen en archivos también denominados paquetes (package). Las instrucciones import situadas al principio del programa sirven para indicar al compilador qué clases externas necesita el programa (aquellas que se utilizan pero que no están definidas en el archivo fuente que se va a compilar). Así, en nuestro ejemplo, nuestro programa necesita las clases java.lang.System y java.io.PrintStream. Esto se indica con la instrucción import. Se podría escribir al principio del programa:

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

Dado que un programa Java suele utilizar varias decenas de clases externas, resultaría tedioso escribir todas las funciones import necesarias. Las clases se han agrupado en paquetes, por lo que se puede importar el paquete completo. Así, para importar los paquetes java.lang y java.io, se escribirá:

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

El paquete java.lang contiene todas las clases básicas de Java y el compilador lo importa automáticamente. Por lo tanto, al final solo escribiremos:

import java.io.*;

2.6. Gestión de excepciones

Muchas funciones de Java pueden generar excepciones, es decir, errores. Ya nos hemos encontrado con una función de este tipo, la función readLine:


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

Cuando una función puede generar una excepción, el compilador de Java obliga al programador a gestionarla con el fin de obtener programas más resistentes a los errores: siempre hay que evitar que una aplicación se «cuelgue» de forma imprevista. En este caso, la función readLine genera una excepción si no hay nada que leer, por ejemplo, porque se ha cerrado el flujo de entrada. La gestión de una excepción se realiza según el siguiente esquema:

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

Si la función no genera ninguna excepción, se pasa a la siguiente instrucción; en caso contrario, se pasa al cuerpo de la cláusula catch y, a continuación, a la siguiente instrucción. Cabe destacar lo siguiente:

  • e es un objeto derivado del tipo Exception. Se puede ser más preciso utilizando tipos como IOException, SecurityException, ArithmeticException, etc.: existen unos veinte tipos de excepciones. Al escribir catch (Exception e), se indica que se quieren gestionar todos los tipos de excepciones. Si el código de la cláusula try puede generar varios tipos de excepciones, es posible que se quiera ser más preciso gestionando la excepción con varias 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
  • Se puede añadir una cláusula «finally» a las 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

En este caso, independientemente de si se produce una excepción o no, el código de la cláusula finally siempre se ejecutará.

  • La clase Exception tiene un método getMessage() que devuelve un mensaje en el que se detalla el error que se ha producido. Por lo tanto, si queremos mostrarlo, escribiremos:
catch (Exception ex){
    System.err.println("L'erreur suivante s'est produite : "+ex.getMessage());
    ...
}//catch
  • La clase Exception tiene un método toString() que devuelve una cadena de caracteres que indica el tipo de la excepción, así como el valor de la propiedad Message. De este modo, se puede escribir:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

También se puede escribir:

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

Aquí tenemos una operación de cadena + Exception que el compilador transformará automáticamente en cadena + Exception.toString() para concatenar dos cadenas de caracteres.

El siguiente ejemplo muestra una excepción generada al utilizar un elemento de matriz inexistente:

// cuadros

// importaciones
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // declaración e inicialización de una matriz
    int[] tab=new int[] {0,1,2,3};
    int i;
     // visualización de una matriz con un bucle «for»
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // generación de una excepción
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//main
}//clase

Al ejecutar el programa se obtienen los siguientes resultados:

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

Aquí hay otro ejemplo en el que se gestiona la excepción provocada por la asignación de una cadena de caracteres a un número cuando la cadena no representa un número:

// importaciones
import java.io.*;

public class console1{
  public static void main(String[] args){
      // creación de un flujo de entrada
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // Se solicita el nombre
    System.out.print("Nom : ");
     // lectura de la respuesta
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // Se solicita la edad
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // Pregunta
      System.out.print("âge : ");
       // lectura y verificación de la respuesta
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // visualización final
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//clase

Algunos resultados de la ejecución:

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. Compilación y ejecución de un programa Java

Compila y ejecuta el siguiente programa:

// importación de clases
import java.io.*;

// clase de prueba
public class coucou{
    // función main
  public static void main(String args[]){
      // visualización en pantalla
    System.out.println("coucou");
  }//main
}//clase

El archivo fuente que contiene la clase coucou anterior debe llamarse obligatoriamente coucou.java:

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

La compilación y ejecución de un programa Java se realiza en una ventana DOS. Los ejecutables javac.exe (compilador) y java.exe (intérprete) se encuentran en el directorio bin del directorio de instalación de 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

El compilador javac.exe analizará el archivo fuente .java y generará un archivo compilado .class. Este no es ejecutable inmediatamente por el procesador. Requiere un intérprete de Java (java.exe), denominado máquina virtual o JVM (Java Virtual Machine). A partir del código intermedio presente en el archivo .class, la máquina virtual generará instrucciones específicas para el procesador del equipo en el que se ejecute. Existen máquinas virtuales de Java para diferentes tipos de sistemas operativos (Windows, Unix, Mac OS, etc.). Un archivo .class puede ejecutarse en cualquiera de estas máquinas virtuales y, por lo tanto, en cualquier sistema operativo. Esta portabilidad entre sistemas es una de las principales ventajas de Java.

Compilemos el 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

Ejecutemos el archivo .class generado:

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

Cabe señalar que en la solicitud de ejecución anterior no se ha especificado el sufijo .class del archivo coucou.class que se va a ejecutar. Se da por supuesto. Si el directorio bin del archivo JDK se encuentra en el directorio PATH de la máquina DOS, no será necesario indicar la ruta completa de los ejecutables javac.exe y java.exe. En ese caso, bastará con escribir

javac coucou.java
java coucou

2.8. Argumentos del programa principal

La función principal main admite como parámetros una matriz de cadenas: String[]. Esta matriz contiene los argumentos de la línea de comandos utilizada para ejecutar la aplicación. Así, si se ejecuta el programa P con el comando:

        java P arg0 arg1 … argn

y si la función main se declara de la siguiente manera:

public static void main(String[] arg);

tendremos arg[0]="arg0", arg[1]="arg1" … He aquí un ejemplo:


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]);
  }
}

Los resultados obtenidos son los siguientes:

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

2.9. Pasar parámetros a una función

Los ejemplos anteriores solo mostraban programas Java con una única función, la función principal main. El siguiente ejemplo muestra cómo utilizar funciones y cómo se produce el intercambio de información entre ellas. Los parámetros de una función siempre se pasan por valor: es decir, el valor del parámetro efectivo se copia en el parámetro formal correspondiente.


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);
  }
}

Los resultados obtenidos son los siguientes:

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

Los valores de los parámetros efectivos «papa» y 20 se han copiado en los parámetros formales S y a. A continuación, estos se han modificado. Los parámetros efectivos, por su parte, no han sufrido cambios. Cabe destacar aquí el tipo de los parámetros efectivos:

  • S es una referencia al objeto c.a.d, es decir, la dirección de un objeto en memoria
  • age es un valor entero

2.10. El ejemplo de los impuestos

Terminaremos este capítulo con un ejemplo que volveremos a utilizar en varias ocasiones a lo largo de este documento. Nos proponemos escribir un programa que permita calcular los impuestos de un contribuyente. Consideraremos el caso simplificado de un contribuyente que solo tiene que declarar su salario:

  • se calcula el número de participaciones del asalariado nbParts = nbEnfants/2 + 1 si no está casado, nbEnfants/2 + 2 si está casado, donde nbEnfants es el número de hijos que tiene.
  • si tiene al menos tres hijos, tiene media parte más
  • se calcula su base imponible R = 0,72 * S, donde S es su salario anual
  • se calcula su coeficiente familiar QF = R / nbParts
  • Se calcula su impuesto I. Consideremos la siguiente tabla:
12 620,0
0
0
13 190
0,05
631
15 640
0,1
1290,5
24 740
0,15
2072,5
31 810
0,2
3309,5
39 970
0,25
4900
48 360
0,3
6898,5
55 790
0,35
9316,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 línea tiene 3 campos. Para calcular el impuesto I, se busca la primera línea en la que QF sea menor o igual que el campo 1. Por ejemplo, si QF = 23000, se encontrará la línea

    24740        0.15        2072.5

El impuesto I es entonces igual a 0,15*R - 2072,5*nbParts. Si QF es tal que la relación QF <= campo1 nunca se cumple, entonces se utilizan los coeficientes de la última línea. En este caso:

    0                0.65        49062

lo que da como resultado el impuesto I = 0,65*R - 49062*nbParts.

El programa Java correspondiente es el siguiente:


import java.io.*;

public class impots{

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

        // datos

        // límites de los tramos impositivos
        double Limites[]={12620, 13190, 15640, 24740, 31810, 39970, 48360,55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // coeficiente aplicado al número de participaciones
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5,12106, 16754.5, 23147.5, 30710, 39312, 49062};

        // el programa

        // creación del flujo de entrada desde el 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);
        }

            // se recupera el 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 hijos
        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

        // salario
        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);
            }// intentar
        }// while

            // cálculo del número de participaciones
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
        
            // renta imponible
        double Revenu;
        Revenu=0.72*Salaire;

            // coeficiente familiar
        double QF;
        QF=Revenu/NbParts;
        
            // búsqueda del tramo impositivo correspondiente a QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // el impuesto
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);

        // se muestra el resultado
        System.out.println("Impôt à payer : " + impots);
    }// página principal

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

}// clase

Los resultados obtenidos son los siguientes:

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