¿Qué sería de los programas sin datos ? ¿Y qué sería de los datos sin herramientas para manejarlos? Eso es lo que vamos a ver en el artículo de hoy. El código que usaremos hoy será el siguiente:

package net.openwebinars;

public class VariablesOperadores {

  public static void main(String[] args) {

    // Variables

    char a = 'a';
    char b = 'b';
    double x = 3.2d;
    float y = 4.8f;
    int auxiliar = 30;
    long numeroCuentas = 10000000000L;
    boolean verdadero = true;   
    String perro = "perro";
    String gato = "gato";    

    // Constantes

    final double NUMERO_PI = Math.PI; // 3.14
    final int CERO = 0;

    // Arrays o Vectores

    String[] paises = {"España", "Italia", "Portugal"};
    String[] animales = new String[] {"perro", "vaca", "gato", "mono"};
    String[] objetos = new String[3]; 

    // Operadores

    objetos[0] = "pelota";
    objetos[1] = "caja";
    objetos[2] = "zapato";

    System.out.println(x + y);
    System.out.println(x - y);
    System.out.println(x * y);
    System.out.println(x / y);
    System.out.println(x % y);

    System.out.println(); 

    System.out.println(numeroCuentas += 1);
    System.out.println(numeroCuentas++);
    System.out.println(++numeroCuentas);

    System.out.println();

    System.out.println(x > y);
    System.out.println(x < y);
    System.out.println(x == y);
    System.out.println(x != y);

    System.out.println();

    System.out.println(String.valueOf(b) + String.valueOf(a));
    System.out.println("El " + perro + " persigue al " + gato);
    System.out.println("El " + animales[0] + " persigue al " + animales[2]);
    System.out.println("perro".equals(animales[0]));
    System.out.println(paises[1].replace('a', '9'));
    System.out.println(paises[1].substring(CERO, 5));
    System.out.println(paises[1]);    
  }

}
Nota: los caracteres ">" y "<" no se ven correctamente a la hora de ponerlos en el artículo. En su lugar para el símbolo ">" usamos gt; (greater than) y en el caso de "<" usamos lt; (less than) con "&" delante. Perdón por las molestias.

Variables

Las variables son secciones reservadas en memoria para almacenar datos los cuales pueden cambiar durante la ejecución del programa. En Java cuando creamos una variable tenemos que seguir la siguiente sintaxis:
Tipo nombreVariable [= valorInicial];
donde:
  • Tipo es la clase de variable que vamos a crear
  • nombreVariable es el nombre que le vamos a dar a dicha variable
He puesto entre corchetes ([]) un elemento opcional a la hora de crear una variable. Las variables al crearlas podemos darle un valor inicial. Para ello hay que usar primero el operador de asignación = seguido del valor inicial. Si vamos al código de ejemplo vemos que
char a = 'a';
char b = 'b';
double x = 3.2d;
float y = 4.8f;
int auxiliar = 30;
long numeroCuentas = 10000000000L;
hemos creado de esta forma 6 variables con valores iniciales. A esto se le conoce como inicialización de variables . A continuación veremos los tipos básicos de variables en Java.

Números enteros ( int )

Las variables de tipo entero o int son aquellas que almacenan un número (ya sea positivo o negativo) no decimal . Debido a que cuando creamos una variable reservamos memoria para ella, cada tipo de variable reservará más o menos memoria para representar el dato que almacenarán. Dicho esto, en el caso de variables de tipo int sólo podemos almacenar números que estén dentro del rango -2^31 y 2^31 - 1 . Si intentamos almacenar un número que esté fuera de ese rango nos dará un error de compilación o de ejecución. Por ejemplo, no podríamos almacenar el número 10000000000 en una variable de tipo int. Un ejemplo sería:
int auxiliar = 30;
Su valor por defecto si no lo inicializamos es 0.

Números enteros grandes ( long )

Las variables de tipo entero grandes o long son aquellas que almacenan un número (ya sea positivo o negativo) no decimal . Las variables de tipo long almacenan números que están dentro del rango -2^63 y 2^63 - 1 . Si intentamos almacenar un número que esté fuera de ese rango nos dará un error de compilación o de ejecución. Para representar que un número es de tipo long, añadimos una L al final del número:
long numeroCuentas = 10000000000L;
Nota: No es recomendable crear una variable de tipo long para almacenar números pequeños debido a que estamos reservando más memoria de la que realmente necesitamos y eso a la larga puede producir que nuestro programa sea mucho más lento de lo que es realmente. Su valor por defecto si no lo inicializamos es 0L.

Números decimales ( double y float )

Si en lugar de números enteros queremos almacenar números decimales, tenemos dos tipos:
  • float: Las variables de tipo float o flotante son aquellos números en precisión simple de 32 bytes en el estandar IEEE 754. Para indicar que un número es de tipo flotante ponemos un punto para separar la parte entera del número de la parte decimal.
  • double: Las variable de tipo double o doble son aquellos números en precisión doble de 64 bytes en el estandar IEEE 754. Para indicar que un número es de tipo flotante ponemos un punto para separar la parte entera del número de la parte decimal.
Si por algún motivo necesitamos especificar si un número es flotante o doble basta con añadir una letra f o d al final del número tal y como vemos en el siguiente código:
double x = 3.2d;
float y = 4.8f;
Añadir que en caso de querer representar números grandes es mejor usar double en lugar de float ya que a la hora de operar con ellos puede producirse errores de aproximación y llevarnos a confusiones innecesarias. Su valor por defecto si no lo inicializamos es 0.0d para double y 0.0f para float. Existen dos tipos básicos más para representar números: short y byte . Estos tipos sólo almacenan números de tipo entero similar a como sucede con las variables de tipo int. No obstante, los rangos de valores que pueden almacenar son mucho más pequeños (byte: -128, 127 short: -32768, 32767) y sólo se suelen usar cuando la reserva de memoria tiene que estar muy controlada para el perfecto funcionamiento de un programa. En general basta con trabajar con variables de tipo int en lugar de estos dos tipos.

Verdadero o Falso ( boolean )

Más adelante veremos herramientas para controlar el flujo de ejecución del programa las cuales se basan en el uso de condiciones ante las cuales el programa se ejecutará de una forma u de otra. Normalmente, esas condiciones serán de la forma:
Si esVerdadero
  Hacer A
Sino 
  Hacer B
Evaluar ese "esVerdadero" no es más que evaluar una sentencia la cual devolverá verdadero ( true ) o falso ( false ) en función de la condición. Ese valor true-false se corresponde con variables booleanas o boolean . Las variables booleanas son aquellas que sólo pueden guardar dos valores: true y false. Se declaran igual que otra variable:
boolean verdadero = true;
Su valor por defecto si no lo inicializamos es false.

Símbolos o caracteres ( char )

Ya hemos hablado de los números, pero ¿qué sucede con las letras o símbolos? Podríamos usar variables de tipo int para almacenarlas, pero al hacer eso en lugar de guardar el símbolo como tal, se almacenaría su correspondiente valor en formato decimal en ASCII y tendríamos que manualmente interpretar dicho número para pasarlo a su correspondiente símbolo si quisieramos por ejemplo imprimirlo por consola. Para evitar esto, tenemos las variables de tipo char :
char a = 'a';
char b = 'b';
En este caso hemos creado dos variables de tipo char; una para el símbolo "a" y otra para el símbolo "b". Notar que para referirnos a un símbolo como tal, tenemos que rodearlo con comillas simples '' . Su valor por defecto si no lo inicializamos es '\u0000'.

Cadenas de texto ( String )

Hemos solucionado el problema de almacenar en memoria símbolos individuales. Supongamos que queremos trabajar con secuencias de símbolos o cadenas de texto . Con lo visto hasta ahora tendríamos que crear tantas variables de tipo char como letras tenga la cadena. Un ejemplo rápido, si quisieramos representar el Quijote con variables char tendríamos un total aproximadamente de 2059005 letras en él contando las letras repetidas. Resulta inviable crear tantas variables de tipo char, ¿verdad? Sin ir tan lejos, para la palabra "perro" tendríamos que crear 5 variables. Para solucionar esto, Java nos facilita el trabajo al definir una clase llamada String la cual representa la secuencia o el vector de símbolos que componen una palabra, una frase, un párrafo, etc. Siguiendo el código del ejemplo,
String perro = "perro";
String gato = "gato";
perro y gato son variables de tipo String las cuales almacenan las cadenas "perro" y "gato" respectivamente. El trabajar así con los símbolos facilita mucho el manejo de cadenas. Su valor por defecto si no lo inicializamos es null . El valor null es el usado en Java para indicar que un Objeto no está inicializado y por tanto no se puede usar.

Constantes ( final )

Supongamos que tenemos un tipo de dato el cual nunca y por ningún motivo cambiará su valor. Por ejemplo el número PI (3.14159265358979323846…). Para indicar que una variable tomará siempre el mismo valor y no se podrá modificar es decir, es constante usamos la palabra reservada final escribiéndola antes del tipo de la variable:
final double NUMERO_PI = Math.PI; // 3.14
final int CERO = 0;
Si intentamos modificar el valor de una constante nos dará error de compilación. Nota: Por cuestiones de buena práctica, se suelen escribir las variables en minúscula y las constantes en mayúsculas. Si el nombre de la variable es compuesto es decir, tiene más de una palabra, la primera letra de las siguientes palabras se escribe en mayúsculas. En el caso de las constantes, se escribe un guión bajo (_) entre palabra y palabra. Por ejemplo NUMERO_PI para la constante y numeroCuentas para la variable.

Arrays o Vectores

Los arrays o vectores son listas donde cada elemento es una variable de un tipo específico con su valor correspondiente. Los arrays no pueden almacenar tipos de variables distintos (realmente eso no es cierto, pero con lo explicado hasta la fecha hay que asumir que sí de modo que lo correcto sería decir "no deberían almacenar tipos de variables distintos"). Existen tres maneras a lo sumo de definir un array:
String[] paises = {"España", "Italia", "Portugal"};
String[] animales = new String[] {"perro", "vaca", "gato", "mono"};
String[] objetos = new String[3];
En la primera estamos creando un array temporal con el nombre de tres países y luego lo almacenamos en la variable paises sin indicar qué tipo de dato va a almacenar; el propio Java se ocupa de reconocerlo. El segundo caso es similar al primero con la diferencia de que especificamos el tipo de valor que va a almacenar nuestro array. El último caso es la forma general (y común en muchos lenguajes) de declarar el array. En él indicamos que será un array de 3 elementos máximo de tipo String, sin inicializar los valores de cada posición o elemento de la lista. Si queremos asignar valores a cada posición del array tendremos que hacerlo de la siguiente forma:
objetos[0] = "pelota";
objetos[1] = "caja";
objetos[2] = "zapato";
Tal y como comenté al explicar la tercera forma de declarar un array, los vectores tienen un tamaño máximo el cual nosotros definimos. Por tanto, no podemos aumentar dicho tamaño; si deseamos un tamaño mayor tenemos que crear un nuevo array y posteriormente asignarle los valores almacenados en el anterior. Para acceder a los elementos almacenados en el vector la sintaxis es la siguiente:
nombreVector[índice];
donde índice será un número entero que esté dentro del rango 0 y tamañoVector - 1 . Hay que tener esto en cuenta ya que cuando queramos acceder a un elemento n-ésimo tendremos que usar el índice (n-1)-ésimo. Así por ejemplo:
System.out.println("El " + animales[0] + " persigue al " + animales[2]);
El mensaje que se muestra por consola es:
El perro persigue al gato
Algo más a tener en cuenta de los vectores en Java es que, a diferencia de otros lenguajes, los vectores no son cíclicos ; si intentamos acceder al siguiente elemento después del último se produce una excepción al usar un índice el cual está fuera de rango. Nota: Java implementa una clase llamada ArrayList la cual extiende los vectores para mejorar su manejo (igual que sucedía con String y las variables de tipo char). No obstante, yo me limitaré a los vectores ya que los ArrayLists no son un elemento de la programación básica. Si alguien quiere usarlos y quiere preguntarme algo de ellos no duraré en responder igualmente.

Clases Envolventes ( Wrappers )

Similar a lo que sucede con los ArrayLists, los Wrappers son una clase propia de Java la cual extiende el uso de una variable básica del lenguaje. Simplemente añaden funcionalidades a los tipos básicos en Java. Los Wrappers existentes y el tipo correspondiente son:
  • Byte para byte.
  • Short para short.
  • Integer para int.
  • Long para long.
  • Float para float.
  • Double para double.
  • Boolean para boolean.
  • Character para char.
Una utilidad muy común en ellos es la de dada una cadena String de un número (por ejemplo "10") transformarla en un número de tipo int y luego operar con ella:
System.out.println(Integer.parseInt("10") + 2);
El resultado de esa sentencia nos imprime por pantalla 12. Si por el contrario esa sentencia fuera esta:
System.out.println("10" + 2);
Java entendería que el número 2 también es una cadena y por tanto concatenaría ambas cadenas e imprimiría por pantalla 102. Un momento... ¿qué es concatenaría? Muy simple: un operador .

Operadores

La información de por si es útil, pero no lo bastante. Necesitamos herramientas con las cuales poder manipularlas, poder hacer operaciones con ellas para obtener nueva información. Los operadores son eso, herramientas para trabajar con las variables. Hay varios tipos de operadores:
  • Aritméticos . Son los operadores matemáticos tal y como los conocemos: Suma (+), Resta (-), División (/), Multiplicación (*) y Resto (%, dado dos números nos devuelve el resto de hacer la división entre ellos). Importante: si los operadores son del mismo tipo de variable, el resultado de aplicar el operador será del mismo tipo que los operadores, mientras que si son de distinto tipo el resultado será del tipo con mayor capacidad; si es un double y un float, el resultado será double.
  • Relacionales . Dados dos valores, comparan si son Iguales (==), uno Mayor (>) o Menor (<) que el otro, Distintos (!=) e incluso Mayor-Igual (>=) o Menor-Igual(<=)
  • Lógicos . Los operadores lógicos son aquellos los cuales sólo devuelven verdadero o falso y se usan para trabajar con variables de tipo boolean. Estos son el operador OR (||), AND (&&) y NOT (!). No te preocupes pues en el siguiente tema los explicaré con más detalle.
  • Operadores a nivel de Bit . Generalmente sólo se usan en casos específicos donde se va a trabajar con los datos en forma de bits directamente. Sólo los nombraré, pero igual que sucedía con los ArrayList; si tienes curiosidad y quieres preguntarme algo sobre ellos no dudes en hacerlo. Estos son: AND (&), OR (|), XOR (^), Desplazamiento a izquierda (<<), Desplazamiento a derecha (>>) y Desplazamiento a derecha rellenando con ceros por la izquierda (>>>)
  • Asignación . Los operadores de asignación se usan para modificar el valor del primer operando. El operador por defecto es la Asignación (=) mencionado anteriormente con el cual inicializamos las variables. Existen también otros operadores de asignación los cuales realizan una operación adicional antes de asignar el nuevo valor al primer operador. Un ejemplo es el operador += el cual suma el primer operando con el segundo y luego almacena el resultado en el primer operando. Hay tantos operadores combinados con el operador asignación como operadores básicos existen (+=, -=, /=, *=, etc)
  • Unitarios . Hasta ahora hemos hablado de operadores con dos operandos. No obstante, también existen operadores que actuan ante un único operando. Ellos son: Signo Negativo (-) el cual si se pone delante de un número estamos indicando que es un número negativo, Incremento y Decremento (++ y --), Complemento a 1 a nivel de bit (~) y el operador NOT (!). Con respecto a los operadores Incremento y Decremento, es muy importante la posición del operador; si va antes de la variable se incrementa/decrementa su valor en 1 primero y luego se almacena, mientras que si va detrás primero se evalua el valor actual y luego se incrementa/decrementa. Por ejemplo:
    long numeroCuentas = 10000000000L;
    ...
    System.out.println(numeroCuentas += 1);
    System.out.println(numeroCuentas++);
    System.out.println(++numeroCuentas);
    En este caso los resultados que se muestran por pantalla son:
    10000000001
    10000000001
    10000000003
  • Operadores de Cadenas . Para trabajar con cadenas tenemos el operador de Concatenación (+) el cual junta dos cadenas en una sola. Es importante recordar que este operador no está definido para trabajar con variables de tipo char de modo que antes de concatenar dos símbolos tenemos que transformarlos en cadenas usando el método String.valueOf() :
    System.out.println(String.valueOf(b) + String.valueOf(a));
    El resultado mostrado por pantalla sería:
    ba
    El operador de concatenación es el único operador aritmético que se puede usar con cadenas mediante el símbolo + ; para restar (o mejor dicho, dividir) una cadena en dos no podemos usar el operador resta. Tampoco podemos usar el operador == para comparar dos cadenas y ver si son iguales. Algunos operadores de cadenas son: Iguales (.equals()), Sustitución (.replace()) usado para reemplazar el primer char por el segundo y Subcadena (.substring()) para obtener una subcadena desde el primer índice dado hasta el segundo. Un ejemplo de cómo se usan es:
    System.out.println("perro".equals(animales[0]));
    System.out.println(paises[1].replace('a', '9'));
    System.out.println(paises[1].substring(CERO, 5));
    cuyo resultado por consola es:
    true
    It9li9
    Itali
    Si se fijan al usar paises[1].replace('a', '9') estamos en primer lugar obteniendo el String almacenado en el array paises en la posición 1 ("Italia" en este caso) y luego llamamos a su método o función replace() la cual sustituye todos los char 'a' en la cadena "Italia" por el char 9. Marco lo de char porque insisto en que ese '9' no es un número tal y como expliqué antes sino un símbolo.

Prioridades de los operadores

Supongamos que tenemos varios operadores en una misma sentencia. ¿Cuál se evaluará primero? ¿Se hace al azar? La respuesta es no. Todos los operadores tienen prioridades entre sí de forma que en caso de duda Java evaluará el que mayor prioridad tenga primero. Una lista ordenada de mayor a menor prioridad de los operadores es (los operadores que están en la misma línea tienen entre sí la misma prioridad): () [] . ++ -- ~ ! new * / % + - >> >>> < >= < <= == != & ^ | && || ?: = += -= *= ... Nota: Los operadores new y ?: son operadores que veremos más adelante. Por si tienes curiosidad, el primero es el operador usado para crear una nueva instancia de una clase y el segundo es un operador ternario condicional. Repito, lo veremos más adelante. Y hasta aquí llegamos con el capítulo de hoy. No se olviden de que tienen a su disposición el curso de la asignatura en cursos.openwebinars.net donde pueden hacer ejercicios y/o cuestionarios a modo de autoaprendizaje. No duden en preguntar todo aquello que no entiendan y espero verles en el próximo artículo donde veremos cómo controlar el flujo de nuestros programas. ¡Un saludo!

Listado de capítulos

En esta sección se listan todos los capítulos de este pequeño curso:
  1. Introducción
  2. Hello World!