Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> Java

Java 8: Guía de Referencia Rápida Completa

Java 8 - Visión General

Java 8 es una versión mayor del lenguaje de programación Java, lanzada inicialmente el 18 de marzo de 2014. Con esta versión, Java añade soporte para programación funcional, nuevo motor JavaScript, nuevas APIs para manipulación de fecha/hora, nueva API de Streams, entre otras mejoras.

Nuevas Características Principales

Ejemplo Comparativo: Java 7 vs Java 8

Considera el siguiente fragmento de código que ordena una lista de nombres.

Demo en vivo
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;

public class Java8Tester {
    public static void main(String args[]) {
        List<String> names1 = new ArrayList<>();
        names1.add("Mahesh ");
        names1.add("Suresh ");
        names1.add("Ramesh ");
        names1.add("Naresh ");
        names1.add("Kalpesh ");

        List<String> names2 = new ArrayList<>();
        names2.add("Mahesh ");
        names2.add("Suresh ");
        names2.add("Ramesh ");
        names2.add("Naresh ");
        names2.add("Kalpesh ");

        Java8Tester tester = new Java8Tester();
        System.out.println("Ordenación con sintaxis Java 7: ");
        tester.sortUsingJava7(names1);
        System.out.println(names1);

        System.out.println("Ordenación con sintaxis Java 8: ");
        tester.sortUsingJava8(names2);
        System.out.println(names2);
    }

    // Ordenación usando Java 7 (clase anónima)
    private void sortUsingJava7(List<String> names) {
        Collections.sort(names, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s1.compareTo(s2);
            }
        });
    }

    // Ordenación usando Java 8 (expresión lambda)
    private void sortUsingJava8(List<String> names) {
        Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
    }
}

Ejecuta el programa para obtener:

Ordenación con sintaxis Java 7: [ Kalpesh Mahesh Naresh Ramesh Suresh ]
Ordenación con sintaxis Java 8: [ Kalpesh Mahesh Naresh Ramesh Suresh ]

El método sortUsingJava8() usa sort con una expresión lambda como parámetro para definir el criterio de ordenación.

Java 8 - Configuración del Entorno

Configuración Local

Si deseas configurar tu propio entorno para Java, esta sección te guía en el proceso.

Java SE se puede descargar gratis desde:

https://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html

Descarga la versión según tu sistema operativo. Ejecuta el .exe para instalar. Tras la instalación, configura las variables de entorno para apuntar a los directorios de instalación correctos.

Configurar PATH en Windows 2000/XP/7/10/11

Suponiendo que instalaste Java en c:\Program Files\java\jdk:

Configurar PATH en Linux, UNIX, Solaris, FreeBSD

La variable de entorno PATH debe apuntar a donde están los binarios de Java. Consulta la documentación de tu shell si tienes dificultades.

Ejemplo para bash: añade al final de .bashrc:

export PATH=/path/to/java:$PATH

Editores Java Populares

Java 8 - Expresiones Lambda

Las expresiones lambda, introducidas en Java 8, son consideradas la característica más importante. Facilitan la programación funcional y simplifican enormemente el desarrollo.

Sintaxis

parámetro -> cuerpo de la expresión

Características Importantes

Ejemplo de Expresiones Lambda

Crea el siguiente programa en C:\JAVA.

Java8Tester.java

Demo en vivo
public class Java8Tester {
    public static void main(String args[]) {
        Java8Tester tester = new Java8Tester();

        // Con declaración de tipo
        MathOperation addition = (int a, int b) -> a + b;

        // Sin declaración de tipo
        MathOperation subtraction = (a, b) -> a - b;

        // Con return y llaves
        MathOperation multiplication = (int a, int b) -> { return a * b; };

        // Sin return ni llaves
        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        // Sin paréntesis
        GreetingService greetService1 = message -> System.out.println("Hola " + message);
        // Con paréntesis
        GreetingService greetService2 = (message) -> System.out.println("Hola " + message);

        greetService1.sayMessage("Mahesh");
        greetService2.sayMessage("Suresh");
    }

    interface MathOperation {
        int operation(int a, int b);
    }

    interface GreetingService {
        void sayMessage(String message);
    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }
}

Verificar el Resultado

C:\JAVA>javac Java8Tester.java
C:\JAVA>java Java8Tester
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hola Mahesh
Hola Suresh

Puntos clave del ejemplo:

Ámbito (Scope)

Una lambda puede referirse a variables final o effectively final (asignadas una sola vez). Error de compilación si una variable se asigna por segunda vez.

Ejemplo de Ámbito

Java8Tester.java

Demo en vivo
public class Java8Tester {
    final static String salutation = "¡Hola! ";

    public static void main(String args[]) {
        GreetingService greetService1 = message -> System.out.println(salutation + message);
        greetService1.sayMessage("Mahesh");
    }

    interface GreetingService {
        void sayMessage(String message);
    }
}

Verificar el Resultado

¡Hola! Mahesh

Java 8 - Referencias a Métodos

Las referencias a métodos permiten apuntar a métodos por su nombre usando el símbolo ::. Pueden referenciar:

Ejemplo de Referencia a Método

Crea el siguiente programa en C:\JAVA.

Java8Tester.java

import java.util.List;
import java.util.ArrayList;

public class Java8Tester {
    public static void main(String args[]) {
        List<String> names = new ArrayList<>();
        names.add("Mahesh");
        names.add("Suresh");
        names.add("Ramesh");
        names.add("Naresh");
        names.add("Kalpesh");

        names.forEach(System.out::println);
    }
}

Aquí pasamos System.out::println como referencia a método estático.

Verificar el Resultado

C:\JAVA>javac Java8Tester.java
C:\JAVA>java Java8Tester
Mahesh
Suresh
Ramesh
Naresh
Kalpesh

Java 8 - Interfaces Funcionales

Las interfaces funcionales tienen una única funcionalidad. Ejemplo: Comparable con compareTo. Java 8 define muchas interfaces funcionales en java.util.function para uso extensivo en lambdas.

Lista de interfaces funcionales en Java 8 (clic para expandir)
Nº Interfaz y Descripción
1

BiConsumer<T,U>

Operación que acepta dos argumentos y no devuelve resultado.

2

BiFunction<T,U,R>

Función que acepta dos argumentos y produce un resultado.

3

BinaryOperator<T>

Operación sobre dos operandos del mismo tipo, produce resultado del mismo tipo.

4

BiPredicate<T,U>

Predicado (función booleana) de dos argumentos.

5

BooleanSupplier

Proveedor de resultados booleanos.

6

Consumer<T>

Operación que acepta un argumento y no devuelve resultado.

7

DoubleBinaryOperator

Operación sobre dos operandos double, produce double.

8

DoubleConsumer

Operación que acepta un argumento double y no devuelve resultado.

9

DoubleFunction<R>

Función que acepta double y produce resultado.

10

DoublePredicate

Predicado de un argumento double.

11

DoubleSupplier

Proveedor de resultados double.

12

DoubleToIntFunction

Función que acepta double y produce int.

13

DoubleToLongFunction

Función que acepta double y produce long.

14

DoubleUnaryOperator

Operación sobre un operando double que produce double.

15

Function<T,R>

Función que acepta un argumento y produce resultado.

16

IntBinaryOperator

Operación sobre dos enteros que produce int.

17

IntConsumer

Operación que acepta un int y no devuelve resultado.

18

IntFunction<R>

Función que acepta int y produce resultado.

19

IntPredicate

Predicado de un argumento int.

20

IntSupplier

Proveedor de resultados int.

21

IntToDoubleFunction

Función que acepta int y produce double.

22

IntToLongFunction

Función que acepta int y produce long.

23

IntUnaryOperator

Operación sobre un operando int que produce int.

24

LongBinaryOperator

Operación sobre dos long que produce long.

25

LongConsumer

Operación que acepta un long y no devuelve resultado.

26

LongFunction<R>

Función que acepta long y produce resultado.

27

LongPredicate

Predicado de un argumento long.

28

LongSupplier

Proveedor de resultados long.

29

LongToDoubleFunction

Función que acepta long y produce double.

30

LongToIntFunction

Función que acepta long y produce int.

31

LongUnaryOperator

Operación sobre un operando long que produce long.

32

ObjDoubleConsumer<T>

Operación que acepta objeto y double, no devuelve resultado.

33

ObjIntConsumer<T>

Operación que acepta objeto e int, no devuelve resultado.

34

ObjLongConsumer<T>

Operación que acepta objeto y long, no devuelve resultado.

35

Predicate<T>

Predicado de un argumento.

36

Supplier<T>

Proveedor de resultados.

37

ToDoubleBiFunction<T,U>

Función que acepta dos argumentos y produce double.

38

ToDoubleFunction<T>

Función que produce double.

39

ToIntBiFunction<T,U>

Función que acepta dos argumentos y produce int.

40

ToIntFunction<T>

Función que produce int.

41

ToLongBiFunction<T,U>

Función que acepta dos argumentos y produce long.

42

ToLongFunction<T>

Función que produce long.

43

UnaryOperator<T>

Operación sobre un operando que produce resultado del mismo tipo.

Ejemplo de Interfaz Funcional

Predicate<T> es una interfaz funcional con método test(Object) que devuelve boolean.

Crea el siguiente programa en C:\JAVA.

Java8Tester.java

Demo en vivo
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Java8Tester {
    public static void main(String args[]) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // Predicate que siempre devuelve true
        System.out.println("Imprimir todos los números:");
        eval(list, n -> true);

        // Predicate para números pares
        System.out.println("Imprimir números pares:");
        eval(list, n -> n % 2 == 0);

        // Predicate para números > 3
        System.out.println("Imprimir números mayores que 3:");
        eval(list, n -> n > 3);
    }

    public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for (Integer n : list) {
            if (predicate.test(n)) {
                System.out.print(n + " ");
            }
        }
        System.out.println();
    }
}

Verificar el Resultado

C:\JAVA>javac Java8Tester.java
C:\JAVA>java Java8Tester
Imprimir todos los números:
1 2 3 4 5 6 7 8 9
Imprimir números pares:
2 4 6 8
Imprimir números mayores que 3:
4 5 6 7 8 9

Java 8 - Métodos Default

Java 8 introduce implementación por defecto en interfaces para compatibilidad hacia atrás, permitiendo que interfaces antiguas aprovechen lambdas.

Ejemplo: List o Collection no tenían forEach. Añadirlo rompería implementaciones existentes. Java 8 permite default para que List/Collection tengan implementación por defecto de forEach, y las clases que las implementan no necesitan implementarlo.

Sintaxis

public interface Vehicle {
    default void print() {
        System.out.println("¡Soy un vehículo!");
    }
}

Múltiples Defaults

Si una clase implementa dos interfaces con el mismo método default, hay ambigüedad. Dos soluciones:

1. Sobrescribir el método:

public interface Vehicle {
    default void print() { System.out.println("¡Soy un vehículo!"); }
}
public interface FourWheeler {
    default void print() { System.out.println("¡Soy un vehículo de cuatro ruedas!"); }
}

public class Car implements Vehicle, FourWheeler {
    public void print() {
        System.out.println("¡Soy un coche de cuatro ruedas!");
    }
}

2. Invocar el default de la interfaz específica con super:

public class Car implements Vehicle, FourWheeler {
    public void print() {
        Vehicle.super.print();
    }
}

Métodos Default Estáticos

Las interfaces pueden tener métodos estáticos auxiliares desde Java 8.

public interface Vehicle {
    default void print() { System.out.println("¡Soy un vehículo!"); }
    static void blowHorn() { System.out.println("¡Sonando claxon!!!"); }
}

Ejemplo de Método Default

Crea el siguiente programa en C:\JAVA.

Java8Tester.java

Demo en vivo
public class Java8Tester {
    public static void main(String args[]) {
        Vehicle vehicle = new Car();
        vehicle.print();
    }
}

interface Vehicle {
    default void print() { System.out.println("¡Soy un vehículo!"); }
    static void blowHorn() { System.out.println("¡Sonando claxon!!!"); }
}

interface FourWheeler {
    default void print() { System.out.println("¡Soy un vehículo de cuatro ruedas!"); }
}

class Car implements Vehicle, FourWheeler {
    public void print() {
        Vehicle.super.print();
        FourWheeler.super.print();
        Vehicle.blowHorn();
        System.out.println("¡Soy un coche!");
    }
}

Verificar el Resultado

C:\JAVA>javac Java8Tester.java
C:\JAVA>java Java8Tester
¡Soy un vehículo!
¡Soy un vehículo de cuatro ruedas!
¡Sonando claxon!!!
¡Soy un coche!

Java 8 - Streams

Stream es una capa abstracta nueva en Java 8. Permite procesar datos de forma declarativa, similar a SQL.

Ejemplo SQL:

SELECT max(salary), employee_id, employee_name FROM Employee

SQL devuelve automáticamente el empleado con mayor salario sin cálculo explícito. Con Collections en Java, el desarrollador usa bucles y comprobaciones repetidas. Además, con procesadores multi-núcleo, escribir código paralelo es propenso a errores.

Java 8 introduce Stream para procesar datos declarativamente y aprovechar arquitectura multi-núcleo sin código específico.

¿Qué es un Stream?

Representa una secuencia de objetos desde una fuente, soportando operaciones agregadas.

Generar Streams

La interfaz Collection tiene dos métodos:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream()
    .filter(string -> !string.isEmpty())
    .collect(Collectors.toList());

forEach

Nuevo método para iterar cada elemento del stream.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

map

Mapea cada elemento a su resultado correspondiente.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream()
    .map(i -> i * i)
    .distinct()
    .collect(Collectors.toList());

filter

Elimina elementos según criterio.

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = strings.stream().filter(string -> string.isEmpty()).count();

limit

Reduce el tamaño del stream.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

sorted

Ordena el stream.

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

Procesamiento Paralelo

parallelStream es la alternativa para procesamiento paralelo. Fácil cambio entre secuencial y paralelo.

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
long count = strings.parallelStream()
    .filter(string -> string.isEmpty())
    .count();

Collectors

Combinan resultados del procesamiento de elementos del stream. Pueden devolver lista o cadena.

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream()
    .filter(string -> !string.isEmpty())
    .collect(Collectors.toList());
System.out.println("Lista filtrada: " + filtered);

String mergedString = strings.stream()
    .filter(string -> !string.isEmpty())
    .collect(Collectors.joining(", "));
System.out.println("Cadena combinada: " + mergedString);

Estadísticas

Collectors de estadísticas para calcular todas las estadísticas durante el procesamiento de stream.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream()
    .mapToInt(x -> x)
    .summaryStatistics();
System.out.println("Número mayor: " + stats.getMax());
System.out.println("Número menor: " + stats.getMin());
System.out.println("Suma total: " + stats.getSum());
System.out.println("Promedio: " + stats.getAverage());

Ejemplo Completo de Streams

Crea el siguiente programa en C:\JAVA.

Java8Tester.java

Demo en vivo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

public class Java8Tester {
    public static void main(String args[]) {
        System.out.println("Usando Java 7: ");
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
        System.out.println("Lista: " + strings);

        long count = getCountEmptyStringUsingJava7(strings);
        System.out.println("Cadenas vacías: " + count);

        count = getCountLength3UsingJava7(strings);
        System.out.println("Cadenas de longitud 3: " + count);

        List<String> filtered = deleteEmptyStringsUsingJava7(strings);
        System.out.println("Lista filtrada: " + filtered);

        String mergedString = getMergedStringUsingJava7(strings, ", ");
        System.out.println("Cadena combinada: " + mergedString);

        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        List<Integer> squaresList = getSquares(numbers);
        System.out.println("Lista de cuadrados: " + squaresList);

        List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        System.out.println("Lista: " + integers);
        System.out.println("Máximo: " + getMax(integers));
        System.out.println("Mínimo: " + getMin(integers));
        System.out.println("Suma: " + getSum(integers));
        System.out.println("Promedio: " + getAverage(integers));

        System.out.println("Números aleatorios: ");
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            System.out.println(random.nextInt());
        }

        System.out.println("\nUsando Java 8: ");
        System.out.println("Lista: " + strings);

        count = strings.stream().filter(s -> s.isEmpty()).count();
        System.out.println("Cadenas vacías: " + count);

        count = strings.stream().filter(s -> s.length() == 3).count();
        System.out.println("Cadenas de longitud 3: " + count);

        filtered = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
        System.out.println("Lista filtrada: " + filtered);

        mergedString = strings.stream().filter(s -> !s.isEmpty()).collect(Collectors.joining(", "));
        System.out.println("Cadena combinada: " + mergedString);

        squaresList = numbers.stream().map(i -> i*i).distinct().collect(Collectors.toList());
        System.out.println("Lista de cuadrados: " + squaresList);

        System.out.println("Lista: " + integers);
        IntSummaryStatistics stats = integers.stream().mapToInt(x -> x).summaryStatistics();
        System.out.println("Máximo: " + stats.getMax());
        System.out.println("Mínimo: " + stats.getMin());
        System.out.println("Suma: " + stats.getSum());
        System.out.println("Promedio: " + stats.getAverage());

        System.out.println("Números aleatorios: ");
        random.ints().limit(10).sorted().forEach(System.out::println);

        // Procesamiento paralelo
        count = strings.parallelStream().filter(s -> s.isEmpty()).count();
        System.out.println("Cadenas vacías (paralelo): " + count);
    }

    // Métodos Java 7 (omitidos por brevedad, igual que original)
    private static int getCountEmptyStringUsingJava7(List<String> strings) { /* ... */ return 0; }
    private static int getCountLength3UsingJava7(List<String> strings) { /* ... */ return 0; }
    private static List<String> deleteEmptyStringsUsingJava7(List<String> strings) { /* ... */ return null; }
    private static String getMergedStringUsingJava7(List<String> strings, String separator) { /* ... */ return ""; }
    private static List<Integer> getSquares(List<Integer> numbers) { /* ... */ return null; }
    private static int getMax(List<Integer> numbers) { /* ... */ return 0; }
    private static int getMin(List<Integer> numbers) { /* ... */ return 0; }
    private static int getSum(List<Integer> numbers) { /* ... */ return 0; }
    private static int getAverage(List<Integer> numbers) { /* ... */ return 0; }
}

Verificar el Resultado

C:\JAVA>javac Java8Tester.java
C:\JAVA>java Java8Tester

La salida muestra la equivalencia entre Java 7 (imperativo) y Java 8 (declarativo con Streams).

Java 8 - Clase Optional

Ver artículo dedicado: Dominando Optional en Java 8

Java 8 - Nashorn JavaScript

Ver artículo dedicado: Motor JavaScript Nashorn en Java 8

Java 8 - Nueva API Date/Time

Ver artículo dedicado: Java 8: La Nueva y Robusta API de Fecha y Hora

Java 8 - Base64

Ver artículo dedicado: Base64 en Java 8: Codificación Simple, URL y MIME Simplificada

Java

  1. Dominando el Mantenimiento Preventivo y Basado en Condición: Guía Práctica de Desarrollo de MP
  2. Guía experta de máquinas curvadoras de tubos cuadrados
  3. Prensas en Frío: Guía Completa para Conformado Metálico Eficiente
  4. Caja de cambios planetaria explicada: reducción de velocidad compacta y de alto par
  5. Fresadora-taladro Jet: la guía profesional definitiva
  6. Prensas servo: funcionamiento y ventajas frente a prensas mecánicas
  7. Guía profesional de cilindros neumáticos: rápidos y fiables
  8. Desbobinador de Engranajes: Beneficios, Funciones y Operaciones
  9. Proteja su cadena de suministro: Estrategias integrales de seguros
  10. Fundamentos de fresado CNC: guía rápida de referencia para operadores profesionales
  11. Entendiendo Java Vector: Uso, Características y Comparación con ArrayList