Académique Documents
Professionnel Documents
Culture Documents
Tabla de Contenido
1
Utilización de paréntesis ........................................................................................................... 19
1.6 Tipos de datos ......................................................................................................................... 20
1.6.1 Fundamentales ................................................................................................................. 20
Enteros .................................................................................................................................. 20
Números en coma flotante ................................................................................................... 20
Carácter ................................................................................................................................. 20
Booleano ............................................................................................................................... 21
Cadenas ................................................................................................................................. 21
Tabla comparativa de tipos de datos simples en Java .......................................................... 21
1.6.2 Definidos por el usuario ................................................................................................... 21
1.7 Palabras reservadas................................................................................................................. 21
1.8 Expresiones ............................................................................................................................. 22
1.9 Estructuras de control ............................................................................................................. 22
1.9.1 Asignación ........................................................................................................................ 23
1.9.2 Selección........................................................................................................................... 23
Sentencia if-else .................................................................................................................... 24
Sentencia switch.................................................................................................................... 27
Operador if-else .................................................................................................................... 30
1.9.3 Iteración ........................................................................................................................... 31
Sentencia while ..................................................................................................................... 33
Sentencia do-while ................................................................................................................ 35
Sentencia for ......................................................................................................................... 36
for mejorado ......................................................................................................................... 37
Ejercicios........................................................................................................................................ 38
Unidad II. Subprogramas ................................................................................................................... 39
2
Unidad I. Fundamentos del Lenguaje
Características de Java
Lenguaje totalmente orientado a Objetos. Todos los conceptos en los que se apoya esta
técnica, encapsulación, herencia, polimorfismo, etc., están presentes en Java.
Disponibilidad de un amplio conjunto de librerías. Como ya se mencionó anteriormente,
Java es algo más que un lenguaje. La programación de aplicaciones con Java se basa no solo
en el empleo del juego de instrucciones que componen el lenguaje, sino, fundamentalmente,
en la posibilidad de utilizar el amplísimo conjunto de clases que Sun pone a disposición del
programador y con las cuales es posible realizar prácticamente cualquier tipo de aplicación.
Lenguaje simple. Java posee una curva de aprendizaje muy rápida. Resulta relativamente
sencillo escribir applets interesantes desde el principio. Todos aquellos familiarizados con C++
encontrarán que Java es más sencillo, ya que se han eliminado ciertas características, como
los punteros. Debido a su semejanza con C y C++, y dado que la mayoría de la gente los
conoce aunque sea de forma elemental, resulta muy fácil aprender Java. Los programadores
experimentados en C++ pueden migrar muy rápidamente a Java y ser productivos en poco
tiempo.
Distribuido Java proporciona una colección de clases para su uso en aplicaciones de red, que
permiten abrir sockets y establecer y aceptar conexiones con servidores o clientes remotos,
facilitando así la creación de aplicaciones distribuidas.
Interpretado y compilado a la vez Java es compilado, en la medida en que su código fuente
se transforma en una especie de código máquina, los bytecodes, semejantes a las
instrucciones de ensamblador. Por otra parte, es interpretado, ya que los bytecodes se
pueden ejecutar directamente sobre cualquier máquina a la cual se hayan portado el
intérprete y el sistema de ejecución en tiempo real (run-time).
Robusto Java fue diseñado para crear software altamente fiable. Para ello proporciona
numerosas comprobaciones en compilación y en tiempo de ejecución. Sus características de
3
memoria liberan a los programadores de una familia entera de errores (la aritmética de
punteros), ya que se ha prescindido por completo los punteros, y la recolección de basura
elimina la necesidad de liberación explícita de memoria.
Seguro (?) Dada la naturaleza distribuida de Java, donde las applets se bajan desde cualquier
punto de la Red, la seguridad se impuso como una necesidad de vital importancia. A nadie le
gustaría ejecutar en su ordenador programas con acceso total a su sistema, procedentes de
fuentes desconocidas. Así que se implementaron barreras de seguridad en el lenguaje y en el
sistema de ejecución en tiempo real.
Indiferente a la arquitectura Java está diseñado para soportar aplicaciones que serán
ejecutadas en los más variados entornos de red, desde Unix a Windows NT, pasando por Mac
y estaciones de trabajo, sobre arquitecturas distintas y con sistemas operativos diversos. Para
acomodar requisitos de ejecución tan diversos o variopintos, el compilador de Java genera
bytecodes: un formato intermedio indiferente a la arquitectura y diseñado para transportar el
código eficientemente a múltiples plataformas hardware y software. El resto de problemas
los soluciona el intérprete de Java.
Portable La indiferencia a la arquitectura representa sólo una parte de su portabilidad.
Además, Java especifica los tamaños de sus tipos de datos básicos y el comportamiento de
sus operadores aritméticos, de manera que los programas son iguales en todas las
plataformas. Estas dos últimas características se conocen como la Máquina Virtual Java (JVM).
Alto rendimiento.
Multihilo. Hoy en día ya se ven como terriblemente limitadas las aplicaciones que sólo
pueden ejecutar una acción a la vez. Java soporta sincronización de múltiples hilos de
ejecución (multithreading) a nivel de lenguaje, especialmente útiles en la creación de
aplicaciones de red distribuidas. Así, mientras un hilo se encarga de la comunicación, otro
puede interactuar con el usuario mientras otro presenta una animación en pantalla y otro
realiza cálculos.
Dinámico El lenguaje Java y su sistema de ejecución en tiempo real son dinámicos en la fase
de enlazado. Las clases sólo se enlazan a medida que son necesitadas. Se pueden enlazar
nuevos módulos de código bajo demanda, procedente de fuentes muy variadas, incluso desde
la Red.
Produce applets Java puede ser usado para crear dos tipos de programas: aplicaciones
independientes y applets. Las aplicaciones independientes se comportan como cualquier otro
programa escrito en cualquier lenguaje, como por ejemplo el navegador de Web HotJava,
escrito íntegramente en Java. Por su parte, las applets son pequeños programas que aparecen
embebidos en las páginas Web, como aparecen los gráficos o el texto, pero con la capacidad
de ejecutar acciones muy complejas, como animar imágenes, establecer conexiones de red,
presentar menús y cuadros de diálogo para luego emprender acciones, etc.
1.2 Comentarios
A medida que los programas se tornen más complejos, podría ser que su código sea difícil
de leer para otros programadores debido a la cantidad de instrucciones que contengan. Ya que
esos programadores tendrán que entender y, posiblemente modifica sus programas debe
escribirlos del modo más legible posible.
Al crear un programa, puedes colocar notas dentro del código fuente con el objeto de
explicar el procesamiento de aquél. Esas notas, llamadas comentarios, no sólo son útiles para que
otros programadores entiendan el programa, también puede ayudar a que recuerdes, después de
4
varios meses de que no has visto el programa, por qué utilizaste esas instrucciones específicas. La
forma más común de incluir un comentario dentro del código del programa es, sencillamente,
colocar dos diagonales, como se muestra enseguida:
//Este es un comentario
Cuando el compilador de Java encuentra dos diagonales, ignora todo el texto que le sigue
en esa misma línea. Al principio de cada coloca debes colocar, cuando menos, comentarios que
indiquen quién es el autor del programa, cuando lo escribió y por qué.
int cuenta_de_usuario;
En una aplicación posiblemente nos encontremos con algún valor que permanece
constante durante la ejecución. Podemos definirla como una variable común pero perderíamos el
control. Por allí, en algún descuido, se cambiaría de valor pero no nos enteraríamos. Podemos
agregar a la definición de variable el modificador final. La sintaxis es la siguiente:
final tipo_variable nombre de variable [= valor];
Por ejemplo:
Además, en muchas ocasiones interesa que el programa guarde los datos que se le han
introducido, de forma que si el programa termina los datos no se pierdan y puedan ser
recuperados en una sesión posterior. La forma más normal de hacer esto es mediante la utilización
de ficheros que se guardarán en un dispositivo de memoria no volátil (normalmente un disco).
5
A todas estas operaciones, que constituyen un flujo de información del programa con el
exterior, se les conoce como Entrada/Salida (E/S).
Existen dos tipos de E/S; la E/S estándar que se realiza con el terminal del usuario y la E/S a
través de fichero, en la que se trabaja con ficheros de disco.
Todas las operaciones de E/S en Java vienen proporcionadas por el paquete estándar de la
API de Java denominado java.io que incorpora interfaces, clases y excepciones para acceder a todo
tipo de ficheros. En este tutorial sólo se van a dar algunas pinceladas de la potencia de este
paquete.
Entrada/Salida estándar
El acceso a la entrada y salida estándar es controlado por tres objetos que se crean
automáticamente al iniciar la aplicación: System.in, System.out y System.err
System.in
Este objeto implementa la entrada estándar (normalmente el teclado). Los métodos que
nos proporciona para controlar la entrada son:
read(): Devuelve el carácter que se ha introducido por el teclado leyéndolo del buffer de
entrada y lo elimina del buffer para que en la siguiente lectura sea leído el siguiente carácter.
Si no se ha introducido ningún carácter por el teclado devuelve el valor -1.
skip(n): Ignora los n caracteres siguientes de la entrada.
System.out
Este objeto implementa la salida estándar. Los métodos que nos proporciona para
controlar la salida son:
print(a): Imprime a en la salida, donde a puede ser cualquier tipo básico Java ya que Java hace
su conversión automática a cadena.
println(a): Es idéntico a print(a) salvo que con println() se imprime un salto de línea al final de
la impresión de a.
System.err
Este objeto implementa la salida en caso de error. Normalmente esta salida es la pantalla
o la ventana del terminal como con System.out, pero puede ser interesante redirigirlo, por
ejemplo hacia un fichero, para diferenciar claramente ambos tipos de salidas.
6
Las funciones que ofrece este objeto son idénticas a las proporcionadas por System.out.
A continuación vemos un ejemplo del uso de estas funciones que acepta texto hasta que
se pulsa el retorno de carro e informa del número de caracteres introducidos.
import java.io.*;
class CuentaCaracteres {
public static void main(String args[]) throws IOException {
int contador=0;
while(System.in.read()!='\n')
contador++;
System.out.println(); // Retorno de carro "gratuito"
System.out.println("Tecleados "+contador+" caracteres.");
}
}
En Java es posible utilizar dos tipos de ficheros (de texto o binarios) y dos tipos de acceso a
los ficheros (secuencial o aleatorio).
Los ficheros de texto están compuestos de caracteres legibles, mientras que los binarios
pueden almacenar cualquier tipo de datos (int, float, boolean, ...).
Una lectura secuencial implica tener que acceder a un elemento antes de acceder al
siguiente, es decir, de una manera lineal (sin saltos). Sin embargo los ficheros de acceso aleatorio
permiten acceder a sus datos de una forma aleatoria, esto es indicando una determinada posición
desde la que leer/escribir.
En el paquete java.io existen varias clases de las cuales podemos crear instancias de clases
para tratar todo tipo de ficheros.
Para tratar con un fichero siempre hay que actuar de la misma manera:
1.- Se abre el fichero. Para ello hay que crear un objeto de la clase correspondiente al tipo de
fichero que vamos a manejar, y el tipo de acceso que vamos a utilizar:
TipoDeFichero obj = new TipoDeFichero( ruta );
7
Donde ruta es la ruta de disco en que se encuentra el fichero o un descriptor de fichero
válido.
Este formato es válido, excepto para los objetos de la clase RandomAccessFile (acceso
aleatorio), para los que se ha de instanciar de la siguiente forma:
RandomAccessFile obj = new RandomAccessFile( ruta, modo );
Donde modo es una cadena de texto que indica el modo en que se desea abrir el fichero;
"r" para sólo lectura o "rw" para lectura y escritura.
2.- Se utiliza el fichero. Para ello cada clase presenta diferentes métodos de acceso para
escribir o leer en el fichero.
3.- Gestión de excepciones (opcional, pero recomendada). Se puede observar que todos los
métodos que utilicen clases de este paquete deben tener en su definición una cláusula
throws IOException. Los métodos de estas clases pueden lanzar excepciones de esta clase
(o sus hijas) en el transcurso de su ejecución, y dichas excepciones deben de ser
capturadas y debidamente gestionadas para evitar problemas.
4.- Se cierra el fichero y se destruye el objeto. Para cerrar un fichero lo que hay que hacer es
destruir el objeto. Esto se puede realizar de dos formas, dejando que sea el recolector de
basura de Java el que lo destruya cuando no lo necesite (no se recomienda) o destruyendo
el objeto explícitamente mediante el uso del procedimiento close() del objeto:
obj.close()
Clase FileOutputStream
Mediante los objetos de esta clase escribimos en ficheros de texto de forma secuencial.
Clase FileInputStream
Mediante los objetos de esta clase leemos de ficheros de texto de forma secuencial.
8
Presenta el método read() para la lectura del fichero. Este método se puede invocar de
varias formas.
import java.io.*;
class MuestraCarta {
public static void main(String args[]) throws IOException {
int c;
FileInputStream f=new FileInputStream("/carta.txt");
while( ( c=f.read() ) != -1 )
System.out.print( (char)c );
f.close();
}
}
Clase RandomAccessFile
Mediante los objetos de esta clase utilizamos ficheros binarios mediante un acceso
aleatorio, tanto para lectura como para escritura. En estos ficheros hay un índice que nos dice en
qué posición del fichero nos encontramos, y con el que se puede trabajar para posicionarse en el
fichero.
Métodos de desplazamiento
Cuenta con una serie de funciones para realizar el desplazamiento del puntero del fichero.
Hay que tener en cuenta que cualquier lectura o escritura de datos se realizará a partir de la
posición actual del puntero del fichero.
Métodos de escritura
La escritura del fichero se realiza con una función que depende el tipo de datos que se
desee escribir.
void write( byte b[], int ini, int len ); Escribe len caracteres del vector b.
9
void write( int i ); Escribe la parte baja de i (un byte) en el flujo.
void writeBoolean( boolean b ); Escribe el boolean b como un byte.
void writeByte( int i ); Escribe i como un byte.
void writeBytes( String s ); Escribe la cadena s tratada como bytes, no caracteres.
void writeChar( int i ); Escribe i como 1 byte.
void writeChars( String s ); Escribe la cadena s.
void writeDouble( double d ); Convierte d a long y le escribe como 8 bytes.
void writeFloat( float f ); Convierte f a entero y le escribe como 4 bytes.
void writeInt( int i ); Escribe i como 4 bytes.
void writeLong( long v ); Escribe v como 8 bytes.
void writeShort( int i ); Escribe i como 2 bytes.
void writeUTF( String s ); Escribe la cadena s utilizando la codificación UTF-8.
Los métodos que escriben números de más de un byte escriben el primero su parte alta.
Métodos de lectura
La lectura del fichero se realiza con una función que depende del tipo de datos que
queremos leer.
Vamos a crear un pequeño programa que cree y acceda a un fichero binario, mediante
acceso aleatorio.
El siguiente ejemplo crear un fichero binario que contiene los 100 primeros números (en
orden):
// Crea un fichero binario con los 100 primeros numeros
static void creaFichBin( String ruta ) throws IOException {
RandomAccessFile f=new RandomAccessFile(ruta,"rw"); // E/S
for ( int i=1; i <= 100 ; i++ )
{
try{
10
f.writeByte( i );
} catch( IOException e){
// Gestion de excepcion de ejemplo
break; // No se puede seguir escribiendo
}
f.close();
}
}
Si incluimos ambos métodos en una clase, y les llamamos con el siguiente programa
principal (main()):
public static void main(String args[]) throws IOException {
String ruta="numeros.dat"; // Fichero
creaFichBin( ruta ); // Se crea
imprimeEltoN( ruta, 14 ); // Accedo al elemento 14.
}
1.5 Operadores
Los operadores, al igual que los métodos, se pueden sobrecargar, es decir se puede
redefinir su funcionalidad dependiendo de los tipos de datos de los operandos que reciba.
Así, podemos indicar que el operador (+) realice una suma aritmética si los operandos que
recibe son dos enteros y una concatenación si recibe una cadena y otro objeto.
11
Operadores aritméticos
Realizan las operaciones aritméticas básicas: suma (+), resta (-), multiplicación (*), división
(/) y módulo o residuo (%) para datos de tipo numérico, tanto enteros como reales. Estas son
operaciones binarias porque admiten dos operandos.
System.out.print("Suma :");
System.out.println(suma );
System.out.print("Resta :");
System.out.println(resta);
System.out.print("Multiplicacion :");
System.out.println(mult);
System.out.print("Division :");
System.out.println(div);
System.out.print("Modulo :");
System.out.println(modulo);
}
Dentro de los operadores aritméticos tenemos los unarios + y – que simplemente operan
con el signo de un valor dado. Por ejemplo:
int h = -1;
int m = +h; // es equivalente a m = h * (+1)
int n = -h; // es equivalente a n = h * (-1)
int i = 1;
i++;
++i;
12
i--;
--i;
Partiendo del mismo valor, vemos que j se incrementó, mientras que la variable i se
mostró sin cambios. Si colocamos el operador como sufijo, primero se evalúa la variable y luego se
realiza la operación. En el caso de la variable i, antes de incrementar su valor se mostró por
pantalla. Para la variable j el procedimiento fue inverso. Antes de mostrar su valor se incrementó.
Operadores relacionales
Revisando algunas definiciones matemáticas, nos enteramos que los números conforman
un conjunto ordenado. Cada uno tiene una posición relativa. Sabemos que el 2 "es menor que" el
4 y que el 6 "es más grande que" el 1. Al comparar dos números, realizamos una función de
relación.
En java disponemos de los operadores relacionales para verificar si se cumple una relación.
Por ejemplo el operador de equivalencia ( == ) nos devuelve un valor de verdadero si los
operandos son iguales. Estas operaciones comparan dos valores numéricos y retorna con un valor
booleano.
Operadores de Relación
Operador Utilización Resultado
> A>B Verdadero si A es mayor que B
>= A >= B Verdadero si A es mayor o igual que B
< A<B Verdadero si A es menor que B
<= A <= B Verdadero si A es menor o igual que B
== A == B Verdadero si A es igual a B
!= A != B Verdadero si A es diferente a B
13
int i = -3;
byte b = 5;
float f = 1e-10f;
double d = 3.14;
boolean b1 = i > i;
boolean b2 = i < b;
boolean b3 = b <= f;
boolean b4 = f >= d;
boolean b5 = d != 0;
boolean b6 = 1 == f;
System.out.println( i + " > " + i + " = " + b1);
System.out.println( i + " < " + b + " = " + b2);
System.out.println( b + " <= " + f + " = " + b3);
System.out.println( f + " >= " + d + " = " + b4);
System.out.println( d + " != " + 0 + " = " + b5);
System.out.println( 1 + " == " + f + " = " + b6);
}
}
No nos olvidemos de los char, que también participan. Podemos comparar caracteres,
pues internamente están almacenados como números.
char a = 'A';
char b = 'B';
boolean x = a > b;
Entre los booleanos solo se permiten los operadores de equivalencia, es igual (==) o es
distinto (!= ).
boolean x = true;
boolean y = x == x;
boolean z = x != y;
Operadores booleanos
Como deben suponer, trabajan con operandos booleanos. Realizan las operaciones lógicas
de conjunción (AND), disyunción (OR), negación ( NOT ) y la disyunción exclusiva ( XOR ).
Operadores Booleanos
Nombre Operador Utilización Resultado
AND && A && B Verdadero cuando A y B son verdaderos. Evaluación
condicional.
OR || A || B Verdadero cuando A o B son verdaderos. Evaluación
condicional.
NOT ! !A Verdadero si A es falso.
AND & A&B Verdadero cuando A y B son verdaderos. Siempre
evalúa ambos operandos.
OR | A|B Verdadero cuando A o B son verdaderos. Siempre
evalúa ambos operandos.
XOR ^ A^B Verdadero cuando A y B son diferentes.
14
Cada una de estas operaciones tiene asociada una tabla de verdad. Esto nos permite ver el
resultado de un operador aplicado a las distintas combinaciones de valores que pueden tener los
operandos. A continuación mostraremos cómo se comporta el operador AND mediante su tabla
de verdad.
public class TablaAnd {
public static void main(String args[]){
boolean x = true;
boolean y = false;
boolean a1 = x && x;
boolean a2 = x && y;
boolean a3 = y && x;
boolean a4 = y && y;
System.out.println("Tabla de verdad de la conjunción");
System.out.println( x + " AND " + x + " = " + a1 );
System.out.println( x + " AND " + y + " = " + a2 );
System.out.println( y + " AND " + x + " = " + a3 );
System.out.println( y + " AND " + y + " = " + a4 );
}
}
Si probamos quitando un ampersand ( & ) del operador, vemos que obtenemos los
mismos resultados. Existen dos operadores AND, uno con dos símbolos & y el otro con uno solo.
También tenemos dos operadores OR.
boolean x1 = operando1 && operando2;
boolean x2 = operando1 & operando2;
Parece extraño, sobre todo porque tienen la misma tabla de verdad. Pero internamente
tienen un comportamiento diferente.
El resultado es falso, pero el intérprete tiene que mirar el segundo operando para saberlo.
boolean x = false && true;
En el caso del operador OR, se evalúa el segundo operador si el primero es falso. Cuando
es verdadero, no tiene en cuenta el otro operando. El resultado es verdadero sin importar el valor
del segundo.
15
Veamos un caso extremo para mostrar cómo funciona la evaluación condicional. Tenemos
el siguiente programa en donde pretendemos hacer saltar al intérprete con un error.
Sin ningún tipo de emoción, aburridamente el intérprete nos avisa que el resultado es
"false". Ahora verá. Quitemos un símbolo & y quedémonos con uno solo. El resultado es otro:
java.lang.ArithmeticException: / by zero
La primera vez verificó que x!=0 era falso, entonces dio por terminada la operación con el
resultado falso. Cuando cambiamos de operador, evaluó los dos operandos y cayó en nuestra
trampa. Tuvo que calcular cuánto es y / x dando luego un error de división por cero.
Los operadores booleanos son muy amigos de los relacionales. Se llevan bien porque los
últimos dan resultados booleanos. Entre ambos tipos de operadores se pueden construir
instrucciones más complejas.
Por ejemplo, queremos saber si un número está dentro de un rango. Solo tenemos que
compararlo con los extremos:
int y = 4;
boolean x = ( y > 3 ) && ( y < 6 );
Ahora deseamos saber si una variable tiene el valor "a" no importando si es mayúscula o
minúscula.
char c = 'b';
boolean x = ( c == 'a' ) || ( c == 'A' );
No olviden que el operador de equivalencia (==) tiene dos símbolos igual (=), si colocan
uno solo les dará un error de asignación.
Operadores de bits
El método más sencillo de representación son los números naturales. Por ejemplo, si
tengo el número 85 en decimal, solo tengo que llevarlo a binario y obtengo una serie de unos y
ceros:
16
1010101 = 85 en binario
Cada dígito (un cero o un uno) de este número se llama bit. Java tiene una serie de
operadores capaces de manipular estos dígitos, son los operadores de bits.
Operadores de Bits
Operador Utilización Resultado
<< A << B Desplazamiento de A a la izquierda en B posiciones.
>> A >> B Desplazamiento de A a la derecha en B posiciones, tiene en
cuenta el signo.
>>> A >>> B Desplazamiento de A a la derecha en B posiciones, no tiene en
cuenta el signo.
& A&B Operación AND a nivel de bits.
| A|B Operación OR a nivel de bits.
^ A^B Operación XOR a nivel de bits.
~ ~A Complemento de A a nivel de bits.
Para operar a nivel de bit es necesario tomar toda la longitud predefinida para el tipo de
dato. Estamos acostumbrados a desechar los ceros a la izquierda en nuestra representación de
números. Pero aquí es importante. Si trabajamos una variable de tipo short con un valor de 3, está
representada de la siguiente manera:
0000000000000011
Operadores de Asignación
algo = algo;
La variable algo toma el valor de algo; todo queda como antes. Ahora aumentemos el
valor de la variable en 3 unidades.
algo = algo + 3;
Aquí la variable toma el valor que tenía más 3 unidades. Existe una forma de simplificar la
notación anterior. Es la siguiente:
17
algo += 3; // equivalente a algo = algo + 3
Se juntaron el operador de suma con el de asignación. Este atajo se puede realizar para
otras operaciones además de la suma. Es útil cuando la operación contiene como primer operando
al valor de la misma variable en la que se almacena el resultado.
Operadores de Asignación
Operación Operador Utilización Operación
Equivalente
Suma += A += B A=A+B
Resta -= A -= B A=A–B
Multiplicación *= A *= B A=A*B
División /= A /= B A=A/B
Residuo %= A %= B A=A%B
Desplazamiento a la izquierda <<= A <<= B A = A << B
Desplazamiento a la derecha >>= A >>= B A = A >> B
Desplazamiento a la derecha sin signo >>>= A >>>= B A = A >>> B
AND de bits &= A &= B A=A&B
OR de bits |= A |= B A=A|B
XOR de bits ^= A ^= B A = A ^B
Precedencia de operadores
Ya que conocimos a los operadores, vamos tratar de colocarlos todos juntos en una sola
expresión. Vamos a ver como se organizan para trabajar:
int j = 10;
boolean esCierto = j/j*j>j-j+j&&j<<j>>>j==j%j||++j<--j+j--;
Precedencia de Operadores
Descripción Operadores
Operadores posfijos Op++ Op--
Operadores unarios ++Op --Op +Op -Op ~ !
Multiplicación y división * / %
Suma y resta + -
Desplazamiento << >> >>>
Operadores relacionales < > <= >=
Equivalencia == !=
Operador AND &
Operador XOR ^
Operador OR |
AND booleano &&
18
OR booleano ||
Condicional ?:
Operadores de asignación = += -= *= /= %= &= ^= |= <<= >>= >>>=
int j = 1 + 3 * 4; // resultado j = 13
Desde que aprendimos aritmética básica, conocemos la regla que nos obliga a calcular la
multiplicación antes de una suma. Esto también se cumple en Java.
int j = 1 + 3 – 4; resultado j= 0;
Utilización de paréntesis
Se utilizan para aislar una porción de la expresión de forma que el cálculo se ejecute de
forma independiente. Puede forzar a una expresión a ignorar las reglas de precedencia.
int j = 1 + 3 * 4; // resultado j = 13
int h = (1 + 3) * 4 // resultado j = 16
int k = 1 + (h = 3);
Cabe agregar que los paréntesis no disminuyen el rendimiento de los programas. Por lo
tanto, agregar paréntesis no afecta negativamente al programa.
19
1.6 Tipos de datos
El trabajo con datos es parte fundamental de cualquier programa, las variables y sus tipos
se encargan de almacenar esa información y la memoria que es necesaria para gestionarlas.
La manera más habitual de declarar una variable siempre contiene dos elementos, el tipo
de la variable y su nombre y terminando la declaración con punto y coma.
Pero también se puede declarar en una misma instrucción más de una variable del mismo
tipo siempre separadas por una coma, al igual que se puede inicializar una variable en el momento
de declararla.
int midato;
tipoVariable nombre;
int midato1 = 3, midato2 = 6,midato3 = 5;
Las variables en Java deben tener un tipo de dato asociado. El tipo de dato de esa variable
indicará los valores que la variable puede contener y las operaciones que se pueden realizar con
ella. Podemos diferenciar los datos en Java en dos categorías de datos principales: los tipos
primitivos y los tipos referenciados.
Los tipos primitivos contienen un sólo valor e incluyen los tipos como los enteros, coma
flotante, los caracteres, de tipo booleano etc. Los tipos referenciados se llaman así porque el valor
de una variable de referencia es una referencia (un puntero) hacia el valor real. En Java tenemos
los arreglos, las clases y las interfaces como tipos de datos referenciados.
1.6.1 Fundamentales
Enteros
Estos tipos son byte, short, int y long, que guardan el signo valor, estos representan un
número y no pueden representar elementos fraccionarios.
Estos son float y double y pueden almacenar números en coma flotante y con signo, esto
quiere decir que nos permiten representar números decimales.
Todos los literales de coma flotante son del tipo double salvo que se especifique lo
contrario, por eso si se intenta asignar un literal en coma flotante a una variable de tipo float el
compilador nos dará un error (tipos incompatibles).
Carácter
Estos son de tipo char, que almacena la representación de los caracteres (letras o
números), un carácter está almacenado en 16 bits, y siguen un estándar que es el Unicode.
20
Los caracteres en Java se pueden especificar de forma normal o con secuencias de escape,
utilizando la barra invertida "\" seguida de una letra (\r) o utilizando la barra invertida con una "u"
seguida de un numero hexadecimal (\u0000d), en este caso hemos especificado la secuencia de
escape \r y su código Unicode correspondiente del retorno de carro.
Booleano
Este solo guarda dos valores: verdadero (true) o falso (false), y no como ocurre en otros
lenguajes que toman los valores 0 y 1. Generalmente su utilización es muy frecuente para
determinar el flujo de los programas.
Cadenas
En Java se tratan como una clase especial llamada String. Las cadenas se gestionan
internamente por medio de una instancia de la clase String. Una instancia de la clase String es un
objeto que ha sido creado siguiendo la descripción de la clase.
abstract catch
boolean char
break class
byte continue
case default
21
do public
double return
else short
extends static
final strictfp
finally super
float switch
for synchronized
if this
implements throw
import throws
instanceof transient
int try
interface void
long volatile
native while
new wesureal
package true (literal booleano)
prívate false (literal booleano)
protected null (literal nulo)
1.8 Expresiones
Hasta el momento, el intérprete se dio un paseo por los ejemplos que hemos visto sin
alterar el curso de ejecución. Una por una ejecutaba las sentencias sin detenerse, ni repetir y sin
saltearse ninguna, salvo si se producía un error. Esto produce programas con poca utilidad y
totalmente aburridos.
Existen ciertas sentencias que permiten modificar el curso de ejecución. Debido a ciertas
condiciones que se dan en el programa podemos decidir que instrucciones se ejecutarán y qué
cantidad de veces. Para lograr esto disponemos de un conjunto de estructuras de control.
22
1.9.1 Asignación
1.9.2 Selección
velocidad_del_vehículo = 0
Estamos frente a una selección simple: tenemos dos alternativas. Este tipo de selección la
condición toma un valor lógico de verdadero o falso. Se tienen que especificar las acciones que
deben ocurrir si la condición es verdadera. Opcionalmente se puede indicar que debe ocurrir si la
condición es falsa. Para lo último veamos un ejemplo.
Imaginemos que estamos en un día de mucho calor y deseamos tomar un refresco. Para
ello nos dirigimos a una máquina expendedora de gaseosas, insertamos una moneda y elegimos el
tipo de bebida. Generalmente una máquina expendedora tiene un panel con botones para realizar
la elección. Internamente dispone de un programa que suelta una lata de acuerdo al botón
pulsado. El algoritmo puede ser similar a esto:
23
Sentencia if-else
Queremos realizar una división de enteros. Es fácil, ya sabemos cómo hacerlo, utilizando
variables y operadores. Pero nos queda un mal recuerdo con la división por cero. Podemos
establecer una condición que permita la división para todos los números y que rechace cualquier
divisor con cara de cero. Disponemos de dos opciones: realizar o no la división. También una
condición: el divisor sea distinto de cero. Esto se parece mucho a una selección simple.
if (condición) sentencia;
¿Qué ocurre si la condición no se cumple? En este caso nada. Podemos agregar una serie
de instrucciones que se ejecutarán solo si la condición no se cumple. Para esto tendremos que
agregar la sentencia else. La estructura de selección quedará así:
if (condición) sentencia 1;
else sentencia 2;
Ahora ampliemos el programa para mostrar una advertencia en el caso que se encuentre
cara a cara con un cero siniestro.
24
public static void main(String args[]){
int x = 12;
int y = 0;
int z = 0;
if( y !=0 ) z = x / y;
else System.out.println("Atención! se pretende dividir por 0");
System.out.println("El resultado es : " + z);
}
}
El programa nos quedó más completo. Con la cláusula else incluimos otra alternativa de
acción. Pero algo anda suelto. Este programa siempre muestra un resultado, se cumpla o no la
condición. El mensaje por pantalla no está incluido en la estructura de selección. Tendremos que
colocarlo dentro del sector de sentencias que se ejecutarán cuando la condición sea verdadera.
Para agrupar las sentencias se utilizan las llaves ( { } ) Indicarán el inicio y el fin de un bloque de
sentencias.
Las buenas prácticas en defensa de un código mantenible han dictaminado que utilicemos
las llaves en todo momento, aún en el caso que utilicemos una sola sentencia.
if (condición) {
sentencia;
} else {
sentencia;
}
Supongamos que deseamos saber si un año es bisiesto. Sabemos que debe ser múltiplo de
4. Para esto tendremos que verificar si el módulo es igual a cero.
año % 4 == 0
25
Pero no debe ser múltiplo de 100.
Los conectores lógicos nos permiten simplificar la estructura. Sin ellos nos veríamos en la
necesidad de anidar las sentencias. Veamos que ocurre si en el ejemplo anterior descartamos el
AND y el OR.
if ( x % 4 == 0 ) {
if ( x % 100 == 0 ) {
if ( x % 400 == 0 ) {
System.out.println("Es bisiesto");
} else {
System.out.println("No es bisiesto");
}
} else {
System.out.println("Es bisiesto");
}
} else {
System.out.println("No es bisiesto");
}
Parece complicado, pero nos demuestra muchas cosas. En primer lugar observamos que se
pueden anidar las sentencias if-else. Cada resultado de una condición puede caer en una nueva
comprobación para formar una estructura compleja de selección.
También vemos que hay cierta relación entre conectores lógicos y la estructura.
Conjunción
if (condición1 && condición2){ if ( condición1 ) {
sentecia1; if ( condición2 ) {
} else { sentencia1;
sentencia2; } else {
} sentencia2;
}
} else {
sentencia2;
}
26
Disyunción
if ( condición1 || condición2 ) { if ( condición1 ){
sentencia1; sentencia1;
} else { } else {
sentencia2; if ( condición2 ) {
} sentencia1;
} else {
sentencia2;
}
}
Negación
if ( ! condición1) { if ( condición1) {
sentencia1; sentencia2;
} else { } else {
sentencia2; sentencia1;
} }
Sentencia switch
Ya nos alejamos bastante de las decisiones simples. Aquí tenemos de una cadena de
sentencias if-else que realizan una selección múltiple. La condición general tiene más dos
alternativas. Tendremos que acudir a la sentencia switch que se encarga de este tipo de selección.
27
switch ( op ) {
case '+':
System.out.println( a + b );
break;
case '-':
System.out.println( a - b );
break;
case '*':
System.out.println( a * b );
break;
case '/':
System.out.println( a / b );
break;
default:
System.out.println("error" );
break;
}
}
}
switch( expresión ) {
case constante1:
sentencia1;
...
break;
...
case constanteN:
sentenciaN;
...
break;
default:
sentencia;
...
break
}
El valor de la expresión y de las constantes tiene que ser de tipo char, byte, short o int. No
hay lugar para booleanos, reales ni long porque, en la ejecución, todos los valores que
incorporamos se transforman en valores de tipo int.
Al evaluar la expresión de switch, el intérprete busca una constante con el mismo valor. Si
la encuentra, ejecuta las sentencias asociadas a esta constante hasta que tropiece con un break. La
sentencia break finaliza la ejecución de esta estructura. Si no encuentra ninguna constante que
coincida con la expresión, busca la línea default. Si existe, ejecuta las sentencias que le siguen. La
sentencia default es opcional.
28
programa figura op) es igual al signo de la suma, la sentencia switch ejecutará solamente la línea
que corresponde con esta operación.
¿Qué ocurre si cambiamos la variable op por algún carácter distinto a los especificados?
Entra en juego la alternativa default y todas las sentencias que le siguen. En este caso imprime por
pantalla el mensaje "error". Si nos olvidamos de incorporar esta alternativa, no pasa nada.
Ninguna sentencia dentro de la estructura switch se ejecutará.
switch ( op ) {
default :
System.out.println("error");
break;
case '+':
System.out.println( a + b );
break;
...
Las sentencias break son opcionales. Se utilizan con el propósito de separar las
alternativas. Pero fieles a nuestro estilo de meternos en problemas decidimos que algunos break
deben desaparecer. Probemos que ocurre con este código:
switch ( op ) {
case '+':
System.out.println( a + b );
case '-':
System.out.println( a - b );
break;
...
El resultado es : 2
0
Nos dio los resultados de la suma y la resta. Al no tener un break en la suma, se pasó de
largo y ejecuto la de abajo, que justamente era la resta.
29
public static void main(String args[]){
int j = 2;
switch (j) {
case 5:
System.out.println("********");
case 4:
System.out.println("********");
case 3:
System.out.println("********");
case 2:
System.out.println("********");
case 1:
System.out.println("********");
}
}
}
El programa tiene por objetivo listar un número dado de líneas. Se pueden dibujar hasta 5
líneas trazadas con el símbolo *. La cantidad dependerá del valor de la variable j. Por ejemplo, si j
vale 2, activa la alternativa que tiene esta constante y como no tiene un break que la obstaculice
sigue con la alternativa de abajo.
Operador if-else
variable = op1?op2:op3
El operando op1 debe ser de tipo booleano. Los operandos op2 y op3 pueden ser de
cualquier tipo, pero compatibles entre sí y con la variable que almacene el resultado. Funciona
como una selección simple. De acuerdo al valor lógico del operando op1, si es verdadero el
resultado de la operación es igual al valor del operando op2. De lo contrario, si op1 es falso, el
resultado es el valor del operando op3.
Probemos este nuevo operando. Supongamos que debemos realizar un programa que
calcule la distancia entre dos números. Para lograrlo, tomamos el mayor y le restamos el menor.
Para empezar, veremos cómo se realiza con la cláusula if-else, que ya conocemos.
30
System.out.println("El resultado es: " + j );
}
}
Como cualquier operador silvestre, se puede combinar tranquilamente con el resto para
formar expresiones compuestas. Para verlo, mostramos una expresión equivalente a la anterior.
Se han utilizado los paréntesis debido a que su orden de precedencia es bajísima. De otra
forma se hubiera evaluado la resta antes de las selecciones.
1.9.3 Iteración
Supongamos que nos piden que realicemos un dibujo sencillo que se despliegue por
pantalla. El objetivo es mostrar un cuadrado de 5 filas por 5 columnas trazado con cualquier
carácter. Con los elementos de programación que ya conocemos, realizamos un programa que
cumpla con este requisito.
Básicamente este programa cumple con el objetivo. Pero... ¿No notan que algo anda mal?
Se repitió cinco veces una instrucción. ¿Qué ocurriría si nos solicitaran una figura más grande?
Tendríamos que agregar más líneas de código. Y si en vez de una figura, se les ocurría pedirnos que
listáramos una lista de números del uno al millón, el código sería inmenso. También imagínense lo
que tardaríamos en escribirlo.
31
Sin embargo tenemos un recurso para acudir en cuanto surjan estos problemas. Son las
estructuras de iteración. Una iteración consiste en una repetición de un bloque de sentencias un
numero determinando de veces o hasta que se cumpla una condición.
De esta forma el código puede simplificarse notablemente. Antes de entrar en los detalles
de la implementación con Java, veremos cómo podemos realizar algunas rutinas en pseudocódigo:
Repetir 5 veces :
Imprimir ("*****");
Siguiendo con una segunda aproximación, podríamos agregarle un registro que cuente el
número de iteraciones. Además adicionamos una condición para que indicar que el registro no
debe pasar de cierto número. De esta manera, el pseudocódigo quedará así:
N = 1;
Mientras que N <= 5
Imprimir ("*****");
N = N + 1;
Lo que hicimos fue inicializar el contador, agregar una condición de corte, indicar que
sentencia se debe repetir y finalmente incrementamos el contador. La condición es una expresión
lógica que debe tener un valor de verdadero o falso. En la ejecución, cada vez que termina la
última sentencia vuelve a evaluar la condición, si se cumple sigue la iteración, de lo contrario
termina.
Esta es una estructura de iteración útil para los casos en donde sabemos a priori cuantas
repeticiones se deben ejecutar. Con pocos retoques se pueden realizar iteraciones desconociendo
el número de ciclos.
El resultado es 11001
32
En general, no sabemos cuántas divisiones tendremos que realizar. Pero si sabemos que
debemos llegar a cero con la división. Las tareas que repetimos son las de tomar el resto y el
resultado de la división. Con estos datos en mente, podremos realizar un algoritmo.
DECIMAL = 25;
Mientras que DECIMAL > 0 :
BINARIO = DECIMAL % 2 + BINARIO;
DECIMAL = DECIMAL / 2;
Sentencia while
La condición tiene que tomar un valor booleano (verdadero o falso). Si este valor es
verdadero, se ejecutará la sentencia. Concluida esta acción se vuelve a evaluar la condición.
Proseguirán los ciclos hasta que la condición no cambie a falso.
int n = 0;
while ( n > 0 ) System.out.println("Esto nunca lo verás");
Dentro del conjunto de sentencia que controla, debe existir alguna que cambie el valor de
la condición que se está evaluando.
Teníamos que transformar un número decimal a binario. El programa en java nos queda
de esta manera:
33
public class Dec2Bin{
public static void main(String args[]){
int decimal = 252222;
String binario = "";
while ( decimal > 0 ) {
binario = decimal % 2 + binario;
decimal /= 2;
}
System.out.println(binario);
}
}
Como no sabemos de antemano cuantas vueltas debe dar, simplemente esperamos que el
resultado de las divisiones sucesivas sea igual a cero.
También se pueden realizar ciclos con while en donde ya conocemos, antes de entrar en la
estructura, cuantas vueltas debe dar para terminar. Para esto nos auxiliamos con un contador de
vueltas. Previamente tiene que inicializarse antes de ingresar al ciclo. Luego en cada vuelta se
modificara según la lógica del algoritmo.
Para tener varias veces el asterisco sin necesidad de imprimirlo así "*****", utilizamos
otro ciclo while y otra variable que inicializaremos dentro del ciclo para que se cumpla la cual
llamaremos "contador2", obtendremos el mismo resultado que el anterior, el código quedaría así:
34
}
}
}
Sentencia do-while
La sentencia de iteración do-while es de tipo posprueba. Primero realiza las acciones luego
pregunta. La sintaxis es la siguiente:
Resulta útil para los casos en donde tendremos que realizar ciertas acciones antes de
verificar una condición.
Realicemos un programa que cuente la cantidad de dígitos que posee un número. Para ello
tendremos que dividir por diez el número que nos han dado, hasta que el resultado se vuelva cero.
Entonces recurrimos al while para realice los ciclos necesarios.
¿Qué ocurre si el número que nos dan es el cero? El resultado nos dará cero. Obviamente
es erróneo, debería devolver un dígito. Pero no entra en el ciclo debido a que de entrada no
satisface la condición. Podríamos implementar una solución "ad hoc".
número /=10;
dígitos++;
while ( número > 0 ) {
número /=10;
dígitos++;
}
35
public class CuentaDigitos{
public static void main(String args[]){
int número = 4557888;
int dígitos = 0;
do {
número /=10;
dígitos++;
}
while ( número > 0 );
System.out.println(dígitos);
}
}
Sentencia for
System.out.println("3 x 1 = 3");
System.out.println("3 x 2 = 6");
System.out.println("3 x 3 = 9");
System.out.println("3 x 4 = 12");
System.out.println("3 x 5 = 15");
System.out.println("3 x 6 = 18");
System.out.println("3 x 7 = 21");
System.out.println("3 x 8 = 24");
System.out.println("3 x 9 = 27");
Pero ya conocemos las estructuras que nos ahorran el esfuerzo de escribir tanto código.
Utilizaremos una sentencia que ya conocemos: el while.
int factor = 1;
while ( factor <= 9 ) {
System.out.println("3 x " + factor + " = " + 3*factor );
factor++;
}
Veremos cómo este código cambia ligeramente si en lugar de while presentamos una
nueva sentencia denominada for:
36
for ( int factor = 1; factor <= 9; factor ++ ) {
System.out.println("3 x " + factor + " = " + 3*factor );
}
La sentencia for me permite repetir un ciclo n veces, en donde se debe determinar el valor
inicial y cuantas veces se repetirá.
Sintaxis:
for ( ;;){}
Operador coma:
for mejorado
Java ofrece una funcionalidad extra para la orden for, mediante la que se puede simplificar
notablemente el código anterior, quedando así:
En este caso, liElemento toma el valor de cada uno de los elementos de laiEnteros,
permitiendo una navegación más simple, puesto que se evitan posibles errores derivados del uso
de los arreglos en forma directa. También se puede usar esta forma, para estructuras más
complejas como objetos de la clase Collection
37
Ejercicios
1.- Crear una aplicación de consola en donde el usuario proporcione un número entero mayor
que 0 y el programa deberá determinar si ese número es primo o no.
2.- Crear una aplicación de consola que determine, de entre los números enteros del 1 al 5000,
cuál de ellos es un número es primo y cuál no lo es.
3.- Crear una aplicación de consola en donde se obtenga el resultado del cálculo de la siguiente
serie: 5 + 2/2 + 3/4 + 4/8 + 5/16 + 6/32 + 7/64 + 8/128 + 9/256 + 10/512.
4.- Crear una aplicación de consola en donde se obtenga el resultado del cálculo de la siguiente
serie: 10 + 1/2 + 2/4 + 3/6 + 4/8 + 5/10 + 6/12 + 7/14 + 8/16 + 9/18 + 10/20.
5.- Crear una aplicación de consola en donde se obtenga el resultado del cálculo de la siguiente
serie: 2 + ((1/2)+1) + ((2/4)+3) + ((3/6)+5) + ((4/8)+7) + ((5/10)+9) + ((6/12)+11) + ((7/14+13) +
((8/16)+15) + ((9/18)+17) + ((10/20)+19).
6.- Crear una aplicación de consola en donde se obtenga el resultado del cálculo de la siguiente
serie: 1 + (1/2) + ((2/4)+3) + ((3/6)+6) + ((4/8)+9) + ((5/10)+12) + ((6/12)+15) + ((7/14+18) +
((8/16)+21) + ((9/18)+24) + ((10/20)+27).
7.- Leer el radio de un círculo y calcular e imprimir superficie y circunferencia. Superficie = PI *
Radio ^ 2. Longitud = 2 * PI * Radio.
8.- Cálculo de los salarios de los empleados de una empresa, sabiendo que éstos se calculan en
base a las horas semanales trabajadas y de acuerdo a un precio especificado por cada hora. Si
se pasan de 40 horas semanales, las horas extraordinarias se pagarán a razón de 1.5 veces la
hora ordinaria.
9.- Crear una aplicación que lea una secuencia de 20 valores enteros (positivos y negativos). El
programa deberá calcular el promedio de los valores positivos y el promedio de los valores
negativos. A su vez, deberá expresar cuántas veces se proporcionó el valor 0.
10.- Desarrollar una aplicación de consola que imprima la serie de números pares entre 0 y 1000.
11.- Crear una aplicación de consola en donde el usuario proporcione una secuencia de números
enteros a través del teclado. La lectura de la secuencia deberá terminar cuando el usuario
proporcione el valor 0. Para finalizar, el programa deberá determinar cuántos valores fueron
pares.
12.- Crear una aplicación de consola en donde se lean 3 valores enteros desde teclado. El
programa deberá determinar si la suma de cualquier pareja de ellos es igual al tercer número.
Si se cumple esta condición, escribir “Iguales”, y en caso contrario, escribir “Distintas”. Por
ejemplo, si los números son: 3, 6 y 9, la respuesta es “Iguales”, pues 3 + 6 = 9.
13.- Un corredor de maratón (distancia = 42.195 km) ha recorrido la carrera en 2 horas 25
minutos. Se desea un programa que calcule el tiempo medio en minutos por kilómetro.
14.- Escribir un programa para calcular el área de un triángulo dada la base y la altura. Estos dos
datos deberán ser proporcionados desde teclado por el usuario.
15.- Escribir un programa que determine el área y el volumen de un cilindro cuyas dimensiones de
radio y altura se lean desde teclado.
38
Unidad II. Subprogramas
39