Java Básico en 30 Minutos: Un Autoestudio para Principiantes

Blog

En este artículo veremos las principales características de Java, exploraremos su filosofía y las razones de su popularidad, y escribiremos un par de programas sencillos para aprender su sintaxis y su enfoque de la escritura de código.

Descargo de Responsabilidad

Quiero advertirle de inmediato, para convertirse en un verdadero desarrollador de java desde cero tendrás que pasar veces más de su tiempo. Por mi experiencia puedo decirte que para conseguir definitivamente un buen trabajo aprendiendo el lenguaje y su estructura deberías dedicar 5-6 meses – con un mínimo de 40 horas semanales.

¡Aquí vamos!

Historia del Lenguaje y Requisitos para el Dominio

¿Por qué es tan popular Java? En primer lugar, es un lenguaje antiguo para los estándares de la informática. Tiene más de 25 años (1995). Durante este tiempo se han escrito muchas aplicaciones y librerías y existe probablemente la mayor comunidad de programadores que pueden ayudar a encontrar una respuesta a cualquier pregunta. En segundo lugar, Java se creó pensando en una alta fiabilidad: en aquella época dominaban los lenguajes C y C++, que tenían un alto umbral de entrada: había que vigilar cada línea. Podrías dispararte fácilmente en el pie si haces un mal uso de la herencia múltiple, no limpias la memoria adecuadamente, etc.

Java ha tenido en cuenta estos errores. Dispone de un práctico recolector automático de basura, un sistema desarrollado de excepciones: aparecen las excepciones comprobadas, lo que aumenta significativamente la fiabilidad del código. Ha creado mecanismos más convenientes para trabajar con multihilo, así como ha utilizado la tipificación estática.

Todo esto convirtió a Java en el lenguaje más robusto del mercado, por lo que muchas empresas lo eligieron como lenguaje por defecto y no se arrepintieron.

Una de las características más destacadas era el enfoque de la ejecución del código. No se compiló directamente en binario. El compilador creaba un código de bytes basado en el código fuente, que a su vez se ejecutaba en el ordenador mediante una aplicación especial, la Máquina virtual Java. Este enfoque presentaba una serie de ventajas significativas: el programador podía ejecutar el mismo código en diferentes sistemas operativos y procesadores sin ningún cambio.

Punto a Favor

No hubo necesidad de recompilar el código para la nueva plataforma, por lo que el administrador podía migrar la aplicación a un nuevo servicio con una arquitectura completamente diferente en un par de horas sin involucrar a los programadores.

La segunda ventaja importante era que, con cada nueva versión, la máquina virtual Java obtenía nuevas características que permitían optimizar el código sobre la marcha. El mismo código se ejecutaba cada vez más rápido con cada nueva versión, ¡sin ninguna intervención del programador!

Recientemente, Java ha cambiado a un nuevo ciclo de publicación: cada nueva versión se publica seis meses después. Esto permite una entrega más rápida de nuevas características en el lenguaje y salva casi por completo la brecha entre el lenguaje y otros lenguajes jvm.

Importante

Puede que muchas de las ventajas no se entiendan ahora, pero al estudiar java te darás cuenta de lo grandes que son y de cómo Java ha marcado el desarrollo de la informática en su momento.

Preparar el Entorno

En primer lugar necesitamos descargar el JDK, que es la máquina virtual, y un conjunto de utilidades que nos permitirán construir el código. Después podemos empezar a programar en nuestro editor favorito. Si no tienes uno, te recomiendo que descargues e instales IntelliJ IDEA Community. Es el editor de código fuente Java más popular y la versión básica se distribuye gratuitamente.

Una vez que hemos descargado todo y lanzado el editor, vamos a empezar a explorar.

Objetos y Métodos en Java

En Java, todo es un objeto. ¿Qué es un objeto? Es una entidad que describe su estado con algunas variables y su comportamiento con funciones/métodos. Veamos un ejemplo del mundo real.

Tenemos un Auto (car), tiene muchas características. Los abstraemos, sólo nos interesan dos parámetros: la velocidad actual (speed) y la velocidad máxima (maxSpeed). En el mundo de la programación orientada a objetos, este enfoque se llama abstracción. ¿Qué comportamiento esperamos de un Auto? Sólo dos: empezar a moverse y parar. Escribamos este código en Java en un archivo llamado car.java:

public class Car {
   int speed;
   int maxSpeed;
  
   void start(){}
   void stop(){}
}

Aquí hemos descrito la plantilla del futuro objeto – una clase. Tiene dos variables de estado, speed y maxSpeed, y dos métodos que describen el comportamiento del objeto.

Ahora la aplicación necesita ejecutarse, para ello Java necesita decirnos dónde está el punto de entrada a la misma. Existe una convención especial para ello: hay que añadir un método a cualquier descripción de objeto:

public static void main(String[] args) {
  
}

Exactamente el código que especifiquemos en él comenzará a ejecutarse.

Ahora ejecuta los siguientes comandos en la consola:

javac Car.java
java Car

O, mucho más fácil, simplemente pulsa la flecha verde junto al método y el editor (IntelliJ IDEA Community):

Ejecutar método main desde IntelliJ IDEA
Ejecutar método main desde IntelliJ IDEA

Nuestra aplicación se ejecuta, pero no ocurre nada porque no hemos añadido ninguna lógica al método. Vamos a añadir una salida de texto simple a la consola:

public static void main(String[] args) {
   System.out.println("Hola Java desde Cero");
}

El resultado de la ejecución puede verse en la consola.

Resultado en consola del método void main
Resultado en consola del método void main

Ten en cuenta que cada archivo sólo puede contener una clase pública. Es decir, la palabra clave public junto con la palabra class.

Imporante

La palabra clave public es un modificador de acceso. Define el nivel de accesibilidad de esta clase/método/variable desde otras partes del programa.

El nombre del archivo debe coincidir con el nombre de la clase, distinguir entre mayúsculas y minúsculas y tener la extensión .java. La palabra clave static indica al compilador que el método/variable pertenece a un modelo de objeto, es decir, a una clase y no a un objeto específico.

No nos centremos en esto por ahora.

Paquetes en Java

Cabe destacar que las clases suelen tener el mismo nombre en los programas, por lo que se sugirió ponerlas en carpetas para que no haya conflicto de nombres. La carpeta donde se encuentra la clase se especifica en la parte superior del archivo:

Estructura de paquetes en Java
Estructura de paquetes en Java

Los creadores sugirieron nombrar estas carpetas como nombres de dominio de Internet (por ejemplo, es.javadesdecero) para distinguirlas con precisión, pero no es necesario, puedes nombrarlas como quieras.

Esto también facilita la importación de clases de otras personas a tu código:

package es.javadesdecero;

import java.util.Random;  // importamos la descripción de la clase del paquete java.util.
public class Import {
   public static void main(String[] args) {
       Random random = new Random();
       System.out.println(random.nextInt());  // mostrar un número aleatorio
   }
 }

No hay ninguna definición de la clase Random en nuestro paquete, así que he utilizado la palabra clave import para añadirla a nuestro programa. Ahora puedo trabajar con él. Usando la palabra clave new creo un objeto aleatorio basado en la clase, que puedo usar en el código posterior. Luego llamo al método nextInt del objeto, que describe el siguiente comportamiento del objeto: el objeto devuelve del método un número natural, que genera aleatoriamente a su manera. No sabemos cómo ocurre exactamente, sólo sabemos que al llamar a este método se obtendrá algún entero de tipo int. En la programación orientada a objetos, esta técnica se llama encapsulación – cuando un objeto genera internamente algún resultado basado en su estado, sin que el usuario de este método sepa cómo funciona bajo el capó.

Programa de número aleatorio de Java
Programa de número aleatorio de Java

Continuemos con el código presentado anteriormente. Empecemos por la más sencilla. Si queremos añadir alguna explicación/comentario al código, podemos insertar dos barras inclinadas (//) en cualquier línea y todo el texto que haya después de ellas será descartado al compilar el programa, pero al visualizar el código fuente será visible.

Creación de Objetos

En el código, teníamos la siguiente línea:

Random random = new Random();

¿Qué hace?

Aquí utilizamos la palabra clave new para crear un nuevo objeto a partir de su plantilla. Especificamos que en nuestro código utilizaremos el nombre random para referirnos a este objeto. En la última línea llamamos al método nextInt que devuelve algún número a nuestro programa y luego pasamos el mismo número al método println que ya lo imprime.

Vamos a intentar crear una clase para nuestro auto y definir su comportamiento:

public class Car {
    void start() {
        System.out.println("Empezar a conducir");
    }

    void stop() {
        System.out.println("Detenerse");
    }

    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.start();
        myCar.stop();
    }
}

Ejecuta el código y ve lo que aparece en la consola.

Ejemplo de creación objetos en Java
Ejemplo de creación objetos en Java

Ahora volvemos a nuestras variables de estado del objeto.

Tipos Primitivos en Java

Los ordenadores trabajan principalmente con números, por lo que se han acuñado varias palabras clave para denotar diferentes tipos de datos, también conocidos como tipos de datos primitivos:

Palabra claveTipoEjemplo
booleantrue o false (número de 8 bits)true
byteNúmero de 8-bit123
shortNúmero de 16-bit123
intNúmero de 32-bit123
longNúmero de 64-bit123L
floatNúmero de 32-bit123.0f
doubleNúmero de 64-bit123.0
charNúmero de 16-bit‘a’

A medida que los ordenadores fueron evolucionando gradualmente, en diferentes etapas de su vida podían almacenar un número que no era mayor que el dígito del procesador en el que funcionaban.

Por eso ha aparecido esta tabla de bits con diferentes números. En nuestro caso, utilizaremos números de tipo int, que pueden describirse con 32 bits en la memoria del ordenador. Es decir, nuestros números estarán entre -2.147.483.648 (-2^31) y 2.147.483.647 (2^31-1).

Constructores de Objetos

Ahora queremos que nuestro comportamiento dependa también del estado interno del objeto. Para ello, tenemos que definirlo de alguna manera. Veamos cómo se puede hacer esto.

public class Car {
    int speed;
    int maxSpeed;

    public Car(int speed, int maxSpeed) {
        this.speed = speed;
        this.maxSpeed = maxSpeed;
        System.out.println("El objeto está listo");

    }

    void start() {
        System.out.println("Empezar a conducir");
        System.out.println(speed);
    }

    void stop() {
        System.out.println("Detenerse");
        System.out.println(maxSpeed);
    }

    public static void main(String[] args) {
        Car myCar = new Car(100, 500);
        myCar.start();
        myCar.stop();
    }

}

Hemos añadido un código especial a nuestro código: el constructor. Nos permite inicializar el objeto antes de empezar a utilizarlo. Al crear el objeto, añadí dos números naturales en el método main, que inicializan el estado del objeto en consecuencia. En el constructor podemos especificar cualquier lógica a realizar al crear el objeto.

Ejemplo de constructor en Java
Ejemplo de constructor en Java

Si ejecutas la aplicación, verás que además de las cadenas/strings, también se muestran números, justo los que pasamos en el constructor. Ahora nuestro objeto está inicializado – tiene algún tipo de estado interno.

Referencias y Tipos Primitivos

Ahora veamos la diferencia clave entre las referencias a objetos, que usamos para trabajar con objetos, y los tipos primitivos. Para las referencias podemos escribir así:

var myCar = new Car(100, 500);
myCar = null;

Hemos equiparado nuestro puntero al objeto con la palabra clave null, que indica a la máquina virtual que este puntero ya no puede ser utilizado para acceder al objeto, es decir, llamar a myCar.start(); provocará un error. ¿Qué ocurre con el objeto que hemos creado? La máquina virtual de Java ejecuta un recolector de basura, que detectará que este objeto vive sin ninguna referencia y lo borrará de la memoria, es decir, lo borrará de la RAM.

Pero, esto no funciona con los tipos primitivos:

int x = null;

Este tipo de código provocará un error.

También hay que tener en cuenta que las cadenas/strings también son clases, pero hay cambios significativos en el lenguaje para ellas.

Las strings son descritas por la clase String. Veamos qué excepciones hay para ellas:

var str = "Me detuve";
var srt2 =  new String("Me detuve");

Esta es la única clase que podemos crear sin el operador new.

Además, las strings pueden sumarse entre sí o con otros tipos primitivos, pero no restarse, dividirse, etc:

System.out.println("Empecé a conducir" + "en dirección a M1");
System.out.println("Empecé a conducir" + "en dirección a M1 con la velocidad " + speed);

Añade estas líneas a nuestro código y verás que todo funciona bien. Pero, de nuevo, esta excepción se hace sólo para una clase – String, porque las strings se utilizan muy a menudo.

Operadores en Java

Ya que hemos mencionado a los operadores, veamos qué ofrece Java.

Un operador unario es un operador que sólo requiere un operando, o variable, y que suele realizar operaciones sencillas.

OperadorDescripciónEjemplo
!Invierte el valor lógico de una función booleana!true será false
+ ó –Indica el signo de un número-123
++Añade uno al númerovar i = 5; i++; //i será igual a 6
Resta uno del númerovar i = 5; i–; //i será igual a 4

A continuación pasamos a los operadores que toman dos argumentos, llamados operadores binarios. Los operadores binarios son los más comunes en Java. Anteriormente hemos visto el operador de suma para strings.

Pueden utilizarse para realizar operaciones matemáticas con variables, crear expresiones lógicas y realizar asignaciones básicas de variables.

OperadorDescripciónEjemplo
+Sumavar i = 5; var k = 6; System.out.println(i + k)
Restavar i = 5; var k = 6; System.out.println(i – k)
*Multiplicaciónvar i = 5; var k = 6; System.out.println(i * k)
/Divisiónvar i = 5; var k = 6; System.out.println(i / k)
%Tomando el módulovar i = 15; var k = 6; System.out.println(i % k)

Si estamos escribiendo una expresión matemática compleja, es mejor utilizar paréntesis:

var x = 5 * (6 – 8);

Me gustaría cerrar la sección de operadores con una tabla de operadores condicionales, cuyo resultado es verdadero (true) o falso (false):

OperadorDescripciónEjemplo
==Comparación de la igualdadvar i = 5; var k = 6; System.out.println(i == k)
< ó <=Menor o menor igualvar i = 5; var k = 6; System.out.println(i < k)
> ó >=Mayor, o mayor igualvar i = 5; var k = 6; System.out.println(i >= k)
&&Operador and (y). Ambas partes deben ser true para que el operador devuelva trueSystem.out.println(true && true)
||Operador or (o). Al menos una parte debe ser true para que el operador devuelva trueSystem.out.println(false || true)

Hemos conocido los operadores más populares en Java, ahora es el momento de utilizarlos.

Queremos que nuestro Auto pueda cambiar su comportamiento, es decir, cambiar la velocidad actual que establecimos al crearlo.

Añadamos un nuevo método que haga esto:

void setSpeed(int speed){
   this.speed = speed;
}

Pero no queremos que nadie que utilice nuestra clase pueda ajustar la velocidad por encima del máximo.

Expresiones Condicionales

Para imponer cualquier restricción a una variable, tenemos que realizar una comprobación, y para ello tenemos que utilizar una expresión condicional if:

void setSpeed(int speed) {
   if (speed < maxSpeed) {
       this.speed = speed;
   }
}

Entre paréntesis ponemos la condición que debe devolver true o false, y entre llaves añadimos el código que se ejecutará si la condición es verdadera (true).

Además, si la condición devuelve false podemos utilizar la palabra clave else para añadir otro bloque de código que se ejecute en ese caso:

void setSpeed(int speed) {
   if (speed < maxSpeed) {
       this.speed = speed;
   }
   else {
       System.out.println("Has recorrido demasiada velocidad");
   }
}

Bucles

¿Qué debemos hacer si queremos repetir un bloque de código muchas veces? Si escribimos while en lugar de if obtenemos el bucle más simple que se ejecutará mientras la expresión entre paréntesis sea verdadera o el bucle no se rompa usando la palabra clave break, o hasta que el programa termine, por ejemplo, desde otro hilo. Este es el aspecto que tendrá:

public static void main(String[] args) {
   var myCar = new Car(100, 500);
   var i = 0;
   while (i < 10){
       myCar.start();
       i++;
   }
}

En este caso, creamos una variable primitiva i inicialmente igual a 0. En el bucle tenemos la condición de que sea menor que 10; si no lo es, el código entre corchetes no se ejecutará. En ellos aumentamos el valor de i en uno, si no lo hiciéramos, el bucle se ejecutaría eternamente. Ejecuta el programa y ve lo que se muestra y cuántas veces.

Para separar esas lógicas de bucle de nuestro código se creó un bucle for.

Encuentra las diferencias:

for (var i = 0; i < 10; i++) {
   myCar.start();
}

Entre paréntesis, creamos un contador, pasamos la condición del bucle y una “fórmula” para saber qué hacer con el contador en cada iteración. Estarás de acuerdo en que así el código parece más compacto y la lógica de control del bucle no se mezcla con nuestra lógica.

Si no pasamos ninguna condición, obtendremos un bucle sin fin:

for( ; ; ) {
   System.out.println("Hello World");
}

No hay manera de salir de ella, excepto terminando la aplicación con el sistema operativo. Podemos terminarlo utilizando la palabra clave break:

for( ; ; ) {
   System.out.println("Hello World");
   break;
}

El mensaje se mostrará en la consola y el bucle se detendrá en este punto.

Arrays y Colecciones (ArrayList)

En nuestro proyecto sólo hemos creado un Auto, ahora vamos a crear varios y ponerlos en algún tipo de almacén.

var myCar = new Car(100, 500);
var myCar2 = new Car(10, 50);
var garage = new Car[2];

garage[0] = myCar;
garage[1] = myCar2;

for (Car car : garage) {
   car.start();
}

En el ejemplo anterior, creamos dos Autos, luego creamos un array de punteros a objetos de la clase Car con tamaño 2 y pusimos punteros a nuestros objetos en él. Como puedes ver, el recuento de las celdas de la matriz comienza con 0. Después, utilizamos una modificación especial del bucle for para arrays y colecciones, que nos permite recorrer todos los elementos y hacer algo de lógica con ellos.

Así, ahora tenemos un objeto que puede almacenar varios punteros a otros objetos, pero no es conveniente trabajar con arrays. Tenemos que saber de antemano el tamaño exacto y en qué celdas tenemos que escribir. Por eso, las colecciones son ahora el método más popular de almacenamiento de datos.

Reescribamos nuestro código utilizando colecciones:

var myCar = new Car(100, 500);
var myCar2 = new Car(10, 50);
var garage = new ArrayList<Car>();

garage.add(myCar);
garage.add(myCar2);

for (Car car : garage) {
   car.start();
}

Como puedes ver, el código no ha cambiado mucho, pero esas torpes entradas de punteros en celdas específicas han desaparecido. Ahora todo se guarda automáticamente.

Para declarar una colección, lo escribimos así:

var garage = new ArrayList<Car>();

¿Qué significa esto? Aquí estamos diciendo que usaremos una colección basada en array y que nuestra colección contendrá objetos como Car.

Lo más importante es que no hemos fijado el tamaño de nuestra colección. Esto se debe a que te permite añadir tantos elementos como la memoria de tu ordenador pueda contener.

Una colección de tipo HashSet (conjunto) no permitirá dos valores idénticos, compara las conclusiones:

var garage = new HashSet<Car>();

garage.add(myCar);
garage.add(myCar);
garage.add(myCar2);

for (Car car : garage) {
   car.start();
}

A continuación, sustituye la primera línea por:

var garage = new ArrayList<Car>();

Además de las listas, también es popular la colección Map, que permite asignar claves a los objetos y luego recuperar esos objetos por una clave única:

var myCar = new Car(100, 500);
var myCar2 = new Car(10, 50);
var garage = new HashMap<String, Car>();

garage.put("Mi auto", myCar);
garage.put("Mi segundo auto", myCar2);

garage.get("Mi segundo auto").start();

He especificado una cadena como clave, una práctica muy común. Y puse mis dos objetos en la colección. Luego usé la llave para obtener mi objeto y llamar a su método.

Puedo decirte que las colecciones son algo que siempre utilizarás en tu trabajo, así que tienes que conocerlas. Aquí he cubierto sólo tres de ellos, que se utilizan el 99% de las veces, sin explicar qué métodos adicionales llevan.

Excepciones

¿Qué pasaría si escribiera mi consulta de la siguiente manera?

garage.get("segundo auto").start();

Verás lo siguiente en la consola:

Exception in thread "main" java.lang.NullPointerException
	at ru.proglib.Car.main(Car.java:42)

Se ha producido una situación excepcional y el programa se ha interrumpido. Porque el método get devolvía null, lo que ya hemos comentado antes. Así que no teníamos un objeto sobre el que pudiéramos llamar al método. El bloque try/catch se inventó para evitar estas situaciones. Veamos cómo puede ayudar a resolver nuestro problema:

try {
   garage.get("segundo auto").start();
}catch (NullPointerException exception){
   System.out.println("No hay ningún auto con esta clave en el diccionario");
}

Después de “try“, escribo código entre llaves, de lo cual no estoy seguro. En el bloque de paréntesis “catch” especifico qué tipo de errores pueden ocurrir. Los errores también son objetos en java. En consecuencia, en llaves especifico la lógica que se ejecutará cuando se produzca una excepción.

Salida

Nuestra breve introducción a Java llega a su fin. En este artículo sólo hemos cubierto una pequeña parte de las características y construcciones del lenguaje. Pero, espero que hayas comprendido que puedes escribir programas concisos y sucintos en él, y que los que crees serán robustos y multiplataforma desde el primer momento.

Java es uno de los lenguajes más populares en el mundo ahora mismo y si lo eliges como lenguaje por defecto, te beneficiarás de ello. A continuación, he enumerado los mejores recursos de los que puede extraer sus conocimientos. ¡Diviértete aprendiendo!

Materiales adicionales:

Sobre el Autor:

Hey hola! Yo soy Alex Walton y tengo el placer de compartir conocimientos hacía ti sobre el tema de Programación en Java, desde cero, Online y Gratis.

Deja una Respuesta

*

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.