En este tutorial de Java interactivo vamos a aprender Java online. Vamos a ver las características principales en varias secciones y veremos un ejemplo en cada sección para poner en práctica la teoría. Es un curso de java gratis para principiantes, ya que no entraremos en profundidad en todas las librerías que ofrece Java.

Como sugerencia, te recomiendo algunos libros de html, libros de css, libros de javascript y libros de Java que sirven para entrar en detalle en estas materias.

El lenguaje Java fue creado por Sun a finales de los años 90, y hasta entonces no ha parado de incrementar su popularidad, hasta situarse en el Top 10 de los lenguajes de programación más utilizados hoy en día.
Principalmente se creó para ser un lenguaje simple, seguro y portable. Se diseñó orientado a objetos y multithreaded. Se creó para poder ejecutarse en cualquier plataforma.

El lenguaje Java simplifica en gran parte llevar la contabilidad de punteros y de memoria, que hacen tan complicado al C++.Dispone de múltipres librerias para trabajar con ficheros y redes (como http).
También es capaz de llevar un control de los típicos errores de ejecución que hay en C++, como es el caso de los punteros nulos, o el acceso a arrays, la limpieza de memoria (gracias al Garbage Collector), y las Exceptions.

Características

Es un lenguaje de programación estructurado y compilado. Es decir, a partir de un código fuente, mediante la compilación obtenemos un fichero binario que se debe ejecutar con un intérprete o máquina virtual de java. Está disponible para Windows, Mac OS, Linux y también para dispositivos móviles (Android). Se compila en "bytecodes" que se ejecutan en una "máquina virtual" de Java. En esta máquina virtual de Java se implementan instrucciones, el area de memoria, la pila, y todo lo necesario para que se pueden ejecutar estos "bytecodes" como si de un procesador se tratara.

Es un lenguaje seguro, ya que dispone de un cargador de classes que es capaz de separar el código local y el código bajado de la red. También añade una protección contra un direccionamiento inválido de memoria, y tiene un verificador de que el código está acorde a lo que especifica la JVM (Java Virtual Machine).
Dispone de un recolector de basura, con lo que no hay que llevar una contabilidad de punteros en memoria.
La sintaxis es poco parecida a C. Aunque la manera de definir el tipo de las variables es precisamente poniendo su tipo al principio de la variable.

En principio está es programación orientada a objetos aunque para los que conocen Java, se puede usar como procedural muy básico.
Es un lenguaje de programación compilado. Se genera código nativo (bytecode) para cada plataforma.
A nivel de concurrencia usa threads, haciendo que la programación concurrente sea más fácil que en C. Así pues Java permite realizar varias tareas simultaneas en un sólo programa.
Se estructura en paquetes (package), y existe un método main, que es el punto de entrada de un programa.

El ejemplo típico de HolaMundo

La secuencia que debemos realizar para ejecutar cada ejemplo es:

Hacer click en el ejemplo .java si el nombre del fichero está en rojo si el nombre del fichero .java está en verde.

Nota: El fichero Hola.class no se puede compilar ni ejecutar. Sirve de ejemplo para ver que son los bytecodes.

Nota: Si el botón está desactivado , no puede realizar ninguna acción.

Para empezar veamos el típico HolaMundo. A la derecha vemos un explorador de archivos ordenado alfabéticamente. Haz click en el fichero HolaMundo.java del explorador de archivos para abrir el fichero en el editor.

La estructura inicial del programa más sencillo es la que podemos ver en el editor Java a la derecha. En esta versión gratuita del tutorial interactivo de Java, casi todas las opciones están deshabilitadas, pero se pueden ver, compilar y ejecutar todos los ejemplos del tutorial online.

/* Ejemplo 1
* El típico Hola mundo!
*/

Estas líneas representan comentarios. También se puede usar el comentario en una sola línea:

//comentarios en una linea

Y también existe el Javadoc que es un tipo de comentario que sirve para generar documentación. Esto es muy útil si queremos hacer una API para que otras personas puedan usar nuestras clases Java y dispongan de un documentación muy detallada.

Se puede ver que las sentencias acaban todas en punto y coma ; y los bloques se engloban entre llaves {}

Todos los programas Java tienen que tener un punto de entrada para poder ejecutarse y ese es precisamente el método main. Este método tiene que ser público (public) y estático (static). Y no tiene que devolver nada (void). Además tiene como parámetro de entrada un array de argumentos (args[]).

El paquete de System, que sirve para leer y escribir por terminal, se usa aquí para escribir en la salida (out) un texto con un salto de línea (println).

Compilar el programa

Prueba a compilar el HolaMundo.java haciendo click en el botón Compilar del menú.

A continuación veremos en la zona inferior de mensajes, que se ha compilado correctamente.

Si estuvieramos en Windows o UNIX, en el Símbolo del sistema o en el terminal de texto, para compilar el programa habría que escribir javac Nombre.java y nos generará un fichero .class. En el caso de que hubiera errores en tiempo de compilación nos los mostraría. Para verlo haz click en el HolaMundoError.java y compílalo como antes.

Como ejercicio, corrige los errores de ese fichero Java y consigue que compile.

Los Bytecodes

Como decíamos anteriormente, el fichero compilado .class contiene bytecodes que se interpretan en una máquina virtual. Para ver con detalle en que consiste un fichero .class, abre el HolaMundo.class y observa la estructura. Como curiosidad, los primeros bytes siempre forman la palabra "cafe babe" en hexadecimal. Es lo que se llama el magic number.

Una vez lo hayas visto, cierra ese fichero del editor, para liberar espacio y ampliar de nuevo el panel de la teoría Java.

Ejecutar el programa

Prueba a abrir el HolaMundo.java y haz click en el botón Ejecutar. Recuerda que antes debes compilarlo para que coja los últimos cambios.

A continuación veremos en la zona inferior de mensajes el resultado de la ejecución: Hola mundo!

Si estuvieramos en Windows o UNIX, en el Símbolo del sistema o en el terminal de texto, para ejecutar el programa habría que escribir java Nombre y nos mostraría por la pantalla: Hola mundo!

En Java los nombres de las variables pueden contener minúsculas, mayúsculas, guiones bajos (_) o dólares ($). También pueden contener números. Pero habitualmente los nombres siguen una nomenclatura "CamelCase", usando sólo mayúsculas y minúsculas.
Existen ciertas palabras clave que no se pueden utilizar como variables, por ejemplo: abstract, boolean, case, catch, continue, int, new, null, etc.
Los tipos de variables en Java son los siguientes:

Tipos primitivos que no son objetos en Java.

boolean - define un valor verdadero o falso, puede tener dos valores "true" o "false".

char - define un carácter Unicode, 'c', '\n', se utiliza entre comillas simples.

byte, short, int, long - definen números enteros con signo de diferentes tamaños. En ese orden serían: 8 bits, 16 bits, 32 bits, 64 bits.

float, double - definen números con coma flotante de diferentes tamaños. En ese orden serían: 32 bits, 64 bits.

Para declarar una variable, se escribe el tipo primero y luego el nombre de la variable:

boolean b; 
int a;
char c;

Para asignar un valor, se utiliza el signo =. Es posible declarar y asignar un valor a la variable al mismo tiempo:

boolean b=true; 
int a=3;
char c='x';

La Clase String

El String define una cadena de texto, entre comillas dobles. Es una clase, y posee ciertas propiedades y métodos.
Cuando no tiene asignado un valor vale "null". Así pues podemos declarar un String b y su valor será "null" mientras no le asignemos un valor concreto. Del mismo modo las variables númericas valen 0 y los boolean valen "false" por defecto.
La clase String posee muchos métodos útiles para comparar cadenas de texto, crear subcadenas, calcular la longitud de la cadena,...

String cadena="Hola";
int longitud = cadena.length();
String subcadena = cadena.substring(1);
if (cadena.equals("Hola)) {
   System.out.println("cadena es igual a Hola");
}
System.out.println("La longitud de cadena es "+longitud);
System.out.println("subcadena es "+subcadena);

Abre el ejemplo CadenasTexto.java compila y ejecuta para ver el resultado.

El ejemplo de tipos de variables

Mira el ejemplo de tipos de variables. Haz click en TiposDatos.java, compila y ejecuta el programa.

Los arrays

Los arrays en Java son arreglos que contienen datos de un mismo tipo. Se declaran con los corchetes (int[]) y se asignan con el operador new y el tamaño dentro de los corchetes.

int[] a = new int[5]; //declaro un array de 5 enteros
String[] l = new String[7]; //decarlo un array de 7 Strings

Cada valor del array se inicializa con un valor por defecto. En el caso de los números es un 0, de los boolean es un false y en el caso de las clases es un null. Una forma rápida de declarar y asignar un array es con las llaves:

String[] colores = { "rojo", "verde", "azul" };
int[] nums =  { 0, 1, 2, 3 };

A su vez se pueden crear arrays que contengan arrays. Se declaran y asignan de este modo:

int coord[][] = new int[4][4];

En Java, los arrays empiezan por el índice 0, y finalizan en el tamaño-1. Así pues en el caso de los colores sería un array de tamaño 3:

Para conocer el tamaño de un array se usa la propiedad length

colores[0] es igual a "rojo";
colores[1] es igual a "verde";
colores[2] es igual a "azul";
colores.length es igual a 3;

El tamaño de los arrays no se puede modificar una vez se ha creado. Para crear arrays dimensionables en Java se puede usar la clase Vector.

El ejemplo de Arrays

Abre el ejemplo Arrays.java, compila y ejecuta el código para ver el resultado.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.

Existen varios operadores en Java: para asignar un valor (x=3), para operar con números (+ - * / %), para comparar variables (== != < > <= >=), para lógica (&& || !), y para operaciones de bit (& | ^ << >>).

Además del habitual ++ -- hay el casting (tipo) variable, que sirve para transformar una variable de un tipo a otro, y el instanceof que sirve para conocer el tipo de una variable.

Es importante comentar que en las expresiones lógicas se usan tipos boolean. Hay otros lenguajes que también usan el int pero en Java no se puede.

Para concatenar cadenas de texto se usa el +. Así pues:

String a="Hola ";
String b="mundo";
String c = a+b;

El resultado de c sería "Hola mundo".

Control de flujo

Sentencias if else

La manera de realizar una comparación de una variable con otra o con un valor es mediante una sentencia if.

if (expresión) {
   sentencias 1
} else {
   sentencias 2
}

Si la expresión es verdadera (true) entonces ejecutará las sentencias 1, en caso contrario ejecutará las sentencias 2. El bloque del else es opcional. Es posible encadenar varias if, else if, else if, else.

Sentencia switch case

Sirve para realizar una comparación de una variable con un int o un char. En función de cada valor (bloque case), se ejecuta las sentencias que haya en cada caso definidas. Si val=1 entrará por el case 1, si val=2 entrará por el case 2, etc... si no es ninguno de los casos entrará por el default.

switch (val) {
   case 1:
      sentencias 1;
      break;
   case 2:
      sentencias 2;
      break;
   case 3:
      sentencias 3;
      break;
   default:
      sentencias 4;
      break;
}

Bucles for

Sirve para realizar bucle.

for (int i=0;i<100;i++) {
   System.out.print(i+" ");
}

Bucles while

Sirve para realizar un bucle mientras una expresión se evalue a "verdadero".

while (expresion) {
   sentencias;
}

Además existen dos palabras reservadas que se usan en este tipo de bucles. break sirve para salir del bucle, y continue sirve para saltar a la siguiente iteración del bucle.

El bucle for también se puede usar de otra manera para Colecciones y arrays.

int[] valores = {20,17,90,43};
for (int v : valores) {
   System.out.println("El valor es "+v);
}

El ejemplo de Operadores, Control de flujo y Bucles

Abre el ejemplo Operadores.java y Bucles.java y compila y ejecuta cada uno para ver el resultado.

El primer ejemplo consta de operadores y usa una sentencia if y un switch. El segundo ejemplo usa un bucle for, y un bucle while. Es interesante ver la utilización de una clase Random del paquete java.util para generar números enteros aleatorios.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.

Java es un lenguaje orientado a objetos. Para ello las clases se organizan en paquetes que se definen al principio del código fuente (package) siguiendo una convención inversa al dominio. Por ejemplo si creamos una app en nuestro domininio sería (online.tutoriales.app). Para utilizar estos paquetes desde otras clases se usa (import paquete.clase) o (import paquete.*) para importar todas las clases que contiene el paquete.

Cada Clase puede tener un tipo de visibilidad: private, donde variables y métodos no se pueden acceder desde fuera de la clase. protected, donde se puede acceder las subclases de ella y public donde se puede acceder desde cualquier clase.

En otros lenguajes para definir estructuras de datos compuestas, se usan los struct. En Java para definir estas estructuras se usan las class, pero dado que Java está orientado a objetos, una clase es algo más que una estructura de datos.

Existen varios tipos de clases, siguiendo el paradigma de orientación a objetos. Una clase final es una clase que no se puede extender o heredar. Una clase abstract es una clase que no contiene implementación sólo definiciones de métodos, son clases para que las clases que la extiendan implementen su propio método.

Por definición para ejecutar una clase tiene que implementar el método public static void main(String args[]), ya que es el punto de entrada para ejecutar un programa Java.

Una clase consta de propiedades y métodos. Las propiedades son variables primitivas o otras clases, y los métodos definen el comportamiento que se realiza con esas propiedades. El esquema de un método es:

public tipoRetorno nombreMetodo (argumentos) {
   sentencias
   return tipoRetorno;
}

Para definir una clase se realiza del siguiente modo:

public class MiClase {
   public int a;
   public String str;
   public void miMetodo(int b){
      return b*a;
   }
}

Cuando tenemos definida una clase, podemos crear instancias de ella, es lo que llamamos objetos de esa clase. Se realiza mediante la palabra new. Luego podemos acceder a sus propiedades y métodos con el punto .

MiClase obj = new MiClase();
System.out.println(obj.a);
System.out.println(obj.str);
System.out.println(obj.miMetodo(4));

Cada objeto en Java es una referencia a los datos (como un puntero), pero en el caso de la clase String siempre hace referencia a una cadena inmutable, que se puede compartir entre varias variables. Así pues:

String a = "Hola";
String b = a;

La variable a y b apuntan (hacen referencia) al mismo sitio, a una cadena inmutable "Hola".

Los métodos y las propiedades en general son public (públicos), aunque se pueden definir como private (privados). De este modo no se puede acceder a ellos desde fuera de la propia Clase. Esto sirve para que nadie pueda modificar el valor de una propiedad desde fuera de la clase, sino es con un método público que tenga esa clase.

Si un método no devuelve nada, se declara como void.

Los métodos suelen tener varios parámetros tanto tipos primitivos como objetos. Incluso a veces pueden tener un número "desconocido" de argumentos, que se indica mediante ...

public Retorno mimetodo(Objeto... objetos) {
  //objetos se trata como si fuera un array de Objeto
}

A veces se utilizan varios métodos con el mismo nombre, que suelen hacen lo mismo (aunque pueden hacer otras cosas) pero con argumentos diferentes, es lo que se llama "sobrecargar" un método.

La palabra reservada this hace referencia al propio objeto cuando se usa dentro de una clase.

Habitualmente una clase siempre implementa "getters" y "setters" para acceder a sus propiedades.

public class MiClase {
   public String txt;
   //getter para la propiedad txt
   public String getTxt(){
      return this.txt;
   }
   //setter para la propiedad txt
   public void setTxt(String txt){
      this.txt=txt;
   }
}

Constructor

Habitualmente para inicializar un objeto se usa el constructor. El constructor es un método especial, que se llama igual que la clase y que no devuelve ningún valor. Se encarga de inicializar las propiedades de la clase. También se puede sobrecargar el constructor para que funcione con argumentos diferentes.

Todas las clases Java tienen un constructor por defecto sino definen uno.

public class MiClase {
   //Constructor
   public MiClase(String txt){
      this.txt=txt;
   }
}

Herencia

Una clase Java puede heredar las propiedades y los métodos de otra clase mediante la palabra extends. Es lo que se llama una subclase. Esto es útil para no duplicar código y para evitar errores. Hay que comentar que los constructores no se heredan entre ellas.

Así por ejemplo podemos definir una clase "Vehículo" y subclases "Coche" y "Moto".

Interfaces

Java proporciona herencia simple, así la clase "Moto" no podría heredar de "Vehículo" y "Ciclomotor". En caso de que necesitarmos que implementara métodos de otra clase, tendríamos que hacerlo con la palabra implements nombreDelInterface.

La clase de la cual heredan todas ellas es Object

Para conocer que tipo de Clase es una variable se usa la palabra instanceof

Ejemplo de objetos

Abre el ejemplo Objetos.java, compila y ejecuta para ver el resultado.

Aunque habitualmente cada clase Java va en su propio fichero, en el ejemplo hemos definido una clase interna dentro de otra clase.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.

En Java para manejar los errores se utilizan clases que extienden de Throwable. Son la clase Error y la clase Exception. Cuando salta una el flujo del programa se acaba. Estas Exception pueden ocurrir por ejemplo cuando se accede a un método de un objeto nulo, un fichero que no se encuentra, un error de comunicaciones, etc. Nosotros podemos definir nuestras propias excepciones para controlar el flujo del programa.

Las de tipo Error serían debidas a condiciones de error no recuperables. En el caso de las de tipo Exception se pueden capturar, y según las condiciones dadas, continuar con la ejecución del programa.

Habría tres tipos de excepciones, las primeras serían cuando se dan condiciones en las que el programa debe recuperarse de esa excepción, por ejemplo al abrir un fichero que no existe. Las segunda serían cuando se dan condiciones que el programa no puede anticipar y son debidas a agentes externos, por ejemplo un servidor de cierra la conexión. Y la tercera es una excepción en tiempo de ejecución, de la que la aplicación a veces no puede recuperarse. Las dos más típicas son NullPointerException y ArrayIndexOutOfBoundsException. La primera ocurre cuando tratamos de acceder a métodos de una variable que no ha sido definida. La segunda ocurre cuando tratamos de acceder a un elemento de un array que está por encima del tamaño de ese array.

El uso de try catch

Para tratar esas excepciones se utilizan las palabras try { } catch {} finally {} y throws. Entre las llaves del try se pone el código que puede lanzar excepciones, en el catch se captura el tipo de Exception concreta, y en finally se pone código que se ejecuta siempre, entre por el try o por el catch. La palabra throws se especifica a nivel de método para indicar que lanza esa Exception hacia arriba, ya que si una Exception no se captura con un catch, se lanza al método que nos ha invocado préviamente. Y así va subiendo en la pila hasta que llega al main y finaliza la ejecución.

El finally se suele utilizar para liberar recursos (ficheros, conexiones, etc...), o hacer limpieza.

try {
   sentencias que pueden lanzar excepciones
} catch (AlgunaException e) {
   sentencias para tratar esa Exception
} finally {
   sentencias para ejecutar una vez haya entrado por el try o por el catch
}

Se pueden definir Excepciones propias de nuestra aplicación, para ello se crea una nueva clase que extiende (hereda) de la clase Exception.

public class MiPropiaException extends Exception {
   sentencias propias
}

Para lanzar esa excepción dentro del programa se haría con:

throw new MiPropiaException();

O para declarar que el método la lanza hacia arriba:

public void miMetodo throws MiPropiaException {
  sentencias
}

Hay una modalidad nueva para hacer un try abriendo recursos que son cerrados automáticamente cuando ya no se necesitan. Esto se hace poniendo entre paréntesis las sentencias que abren ficheros, conexiones, etc... sin necesidad de escribir el finally.

try ( sentencias que abren recursos ){
   sentencias que usan los recursos abiertos
} catch (AlgunaException e) {
   sentencias para tratar esa Exception
} 

Abre el Ejemplo Excepciones.java, compila y ejecuta para ver el resultado.

En este ejemplo se pueden ver varias excepciones en tiempo de ejecución como NullPointer o ArrayIndexOutOfBounds. Como ejercicio modifica el código para evitar que se lance un NullPointer, compila y ejecuta. Luego modifica de nuevo para que no salte un ArrayIndexOutOfBounds, compila y ejecuta.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.

Java dispone de varios paquetes para el tratamiento de entrada y salida (E/S), mediante los Streams. Los Streams son como tuberías por donde circulan los datos de entrada y de salida. El paquete principal es java.io donde se pueden encontrar todo tipo de clases para este uso.
También dispone de paquetes específicos para E/S de ficheros, operaciones con ficheros (copiar, mover, eliminar,...) y acceso aleatorio, en el paquete java.nio.file

E/S con Streams

Hay varios tipos de streams de E/S. Por ejemplo los Byte Streams para manejar datos binarios, los Character Streams para manejar datos en forma de carácteres, o los Buffered Streams que manejan búfferes para optimizar el total de lecturas o escrituras.

En el caso de tratar con ficheros binarios, las clases principales son InputStream para las entradas y OutputStream para las salidas. Estas clases lanzan la excepción IOException que o bien se debe capturar con try catch, o bien se lanza hacia arriba con throws
Es importante cerrar los streams para evitar un uso excesivo de recursos. Esto se realiza siempre en el finally.

En el caso de tratar con ficheros que contienen datos en forma de carácter, es mejor utilizar las clases Reader para las entradas y Writer para las salidas. Luego el funcionamiento es igual a los ficheros binarios, se lanza la excepción IOException y hay que cerrar los recursos abiertos en el finally.

Se pueden realizar las lecturas carácter a carácter con el método read() o línea a línea con el método readLine().

Cuando hay que leer o escribir bastantes datos, es más óptimo utilizar BufferedReader y BufferedWriter y lo mismo para archivos binarios BufferedInputStream y BufferedOutputStream.

E/S de ficheros con nio

Para trabajar con ficheros se suele usar nio. Una de las clases principales es Path que corresponde con una ruta de un fichero. Así pues en Windows tendríamos "C:\Usuarios\Pepe\Documentos" y en UNIX tendríamos "/home/pepe". A partir de esa clase usaremos los métodos de la clase Files para comprobar si existe un fichero, para crearlo, para borrarlo, etc...

//crear un path que apunta a mi home en unix
Path p = Paths.get("/home/pepe");

Para comprobar si un fichero existe, se puede leer, escribir o ejecutar, usaremos los métodos isReadable(Path), isWriteable(Path), isExecutable(Path).

Para eliminar un fichero, usaremos el método delete(Path), para moverlo, usaremos el método move(Path, Path, Options), y para copiarlo usaremos el método copy(Path, Path, Options).

El código para crear un fichero normal sería:

Path p = Paths.get("/home/pepe");
try {
    Files.createFile(p);
} catch (FileAlreadyExistsException x) {
    System.err.format("El fichero %s" + " ya existe%n", p);
} catch (IOException x) {
    System.err.format("Error al crear el fichero: %s%n", x);
}

y para crear un fichero temporal:

try {
    Path temporal = Files.createTempFile(null, ".mio");
    System.out.format("El fichero temporal" + " se ha creado: %s%n", temporal);
} catch (IOException x) {
    System.err.format("IOException: %s%n", x);
}

Ejemplo de creación de ficheros

Vamos a crear un fichero en el directorio /tmp y a borrarlo.

Para verlo en funcionamiento abre el CreaFichero.java y EliminaFichero.java. Prueba a crear el fichero, y luego a borrarlo. Puedes probar a crearlo de nuevo o a borrarlo dos veces.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.

El lenguaje Java, nació con la conectividad en sus genes. Para realizar programas que involucren sockets, y conexiones tcp, tenemos disponible el paquete java.net
También podemos programar conexiones udp para enviar y recibir paquetes de datagramas, y utilizar conexiones http y https, cookies, acceso a recursos, mediante estas apis.
Podemos usar proxies, y tiene soporte a IPv6, entre otras cosas.

Las clases principales se encuentran en el paquete java.net. Para realizar programas con el protocolo TCP podemos usar las clases URL, URLConnection, Socket y ServerSocket y para usar el protocolo UDP podemos usar las clases DatagramPacket, DatagramSocket y MulticastSocket.

URLs

Para localizar y acceder a cualquier recurso en Internet podemos usar la clase URL. Uno de los protocolos más conocidos es http. Para crear un objeto URL podemos proceder así:

URL url = new URL("http://google.es");

Esta clase lanza una MalformedURLException cuando no puede resolver un dominio, que habrá que capturar y manejar el error.

Una vez creada la URL se puede obtener un stream de entrada para leer el contenido de esa URL. Utilizando los streams de la sección anterior, crearemos un BufferedReader a partir de url.openStream().

Ejemplo para leer una URL

Abre el ejemplo LeeURL.java, compila y ejecuta para ver el resultado.

Sockets

A veces necesitamos crear aplicaciones cliente-servidor, para ello solemos utilizar los sockets TCP para crear un servidor que escuche en un puerto determinado y un cliente que se conecte a ese puerto para enviar y recibir datos.

Para crear el servidor usamos la clase ServerSocket(puerto). Luego se crea un Socket con el método accept(). A partir de él, luego se obtienen los Readers y Writers que son streams para enviar y recibir datos entre el cliente y el servidor.

Habitualmente se crea un bucle while que va escuchando hasta que se conecte un cliente y una vez llegue una petición la gestiona en un Thread aparte.

Ejemplo de cliente y servidor

Vamos a ver dos ejemplos. El primero ServidorTCP.java crea un servidor que escucha en el puerto 7654. El segundo ClienteTCP.java crea un cliente que se conecta al servidor, le dice "hola" y luego "exit". Cuando el servidor recibe un "exit", envía "adios" y cierra la conexión con el cliente.

Primero hay que compilar el ServidorTCP y el ClienteTCP.java y luego ejecutar el servidor (que estará escuchando durante un minuto y medio) y justo a continuación hay que ejecutar el cliente. Veremos los mensajes del cliente por la consola.

Al lanzar el servidor se quedará el botón "Ejecutar" en naranja, porque se ejecuta en segundo plano.

Si el cliente muestra por consola un mensaje de "Error E/S" significa que el servidor no se está ejecutando.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.

Una de las funcionalidades que en su día fue innovadora fue la introducción de los Threads en Java. Son "procesos" ligeros como una especie de "cpu" virtual, con sus datos y su propio código que se ejecuta en paralelo a la clase principal main. De hecho el main es un thread también que es capaz de crear otros threads que queramos. En Java disponemos de la clase java.lang.Thread y el paquete java.util.concurrent para la gestión de los threads.

En esta sección sólo vamos a dar cuatro pinceladas de la concurrencia en Java, ya que se podría dedicar un tutorial entero sólo a ello.

Para crear una clase que sea capaz de ejecutar código en un proceso aparte, se usa el interface Runnable. La clase debe implementar ese interface. Una vez definida esa clase se crea un objeto Thread y se le pasa en el constructor la instancia de esa clase que implementa el interface Runnable.

Esa clase que implementa el interfaz Runnable debe sobreescribir el método public void run. Ahí es donde se define el código de la tarea a ejecutar.

Se puede gestionar cada thread con los executors o simplemente invocando a la clase Thread. Cuando se tienen muchos threads es habitual utilizar executors de varios tipos para concretamos lo que necesitamos.

Podemos ver el siguiente ejemplo para crear una clase que es un thread:

//Clase que implementa la interface Runnable y sobrescribe el método run
public class Tarea implements Runnable {
    public void run() {
        System.out.println("Hola desde el thread!");
    }
}
//Clase principal Multitarea llamará a ese thread y lo arrancará
public class Multitarea {
    public static void main(String args[]) {
        (new Thread(new Tarea())).start();
    }
}

Pausando un thread con sleep

Los threads se pueden pausar, haciendo una llamada al método sleep. Se suele definir en milisegundos. Este método se invoca sobre el thread actual y puede lanzar una InterruptedException cuando otro thread interrumpe a este thread mientras duerme.

//Duerme durante 3 segundos
Thread.sleep(3000);

Se puede interrumpir a un thread para que pare o cambie la tarea que está realizando. Como decíamos si el thread está durmiendo se puede capturar la excepción que lo interrumpe, y sino se puede verificar si ha sido interrumpido haciendo una llamada a Thread.interrupted()

Ejemplo con un thread

A continuación abre el ejemplo Multitarea.java y Tarea.java. Primero compila la clase Tarea y luego la clase Multitarea. Luego ejecuta la clase Multitarea que es la que contiene el método main.

Este ejemplo crea un thread que va ejecutando un trabajo y duerme cada 1 segundo. El método main espera 3 segundos y lo interrumpe sino ha acabado y la ejecución se aborta. como ejercicio prueba a poner un par de segundos más a la variable tiempoEspera del método main para ver la diferencia.

Si te gusta este tutorial, puedes contribuir anónimamente con unos tokens BAT.
No conoces Brave? el navegador web que permite navegar más rápido y respetando tu privacidad.
 ◂ 
 ▸