Advanced Java: generics, lambdas and streams
Generics, lambda expressions, the Streams API and the Java 8+ date/time API, with interactive examples.
Introduction to Advanced Java
In this module you'll explore advanced Java features that will let you write more efficient, safe, and modern code. These tools are essential for developing professional applications.
Generics
Parameterized types for reusable, type-safe code
Lambda
Anonymous functions for functional programming
Streams API
Declarative processing of collections
Dates/Times
Modern API for handling dates (Java 8+)
Files
Efficient file reading and writing
Generics (Generics)
Parameterized Types: Write Once, Use Any Type
// CLASE GENÉRICA BÁSICApublic class Caja {
private T contenido;
public void guardar(T contenido) {
this.contenido = contenido;
}
public T obtener() {
return contenido;
}
public void mostrarTipo() {
System.out.println("Tipo de T: " + contenido.getClass().getSimpleName());
}
}
// CLASE GENÉRICA CON MÚLTIPLES PARÁMETROSpublic class Par {
private K clave;
private V valor;
public Par(K clave, V valor) {
this.clave = clave;
this.valor = valor;
}
public K getClave() { return clave; }
public V getValor() { return valor; }
}
// MÉTODO GENÉRICOpublic class Utilidades {
public static boolean esIgual(T obj1, T obj2) {
return obj1.equals(obj2);
}
public static > T maximo(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
}
Wildcards
Upper Bounded
Accepts the specified type or its subclasses
List extends Number> lista;
Lower Bounded
Accepts the specified type or its superclasses
List super Integer> lista;
Unbounded
Accepts any type (read-only)
List> lista;
Lambda Expressions
Functional Programming in Java
Lambda expressions allow implementing functional interfaces concisely:
// INTERFAZ FUNCIONAL (un solo método abstracto)@FunctionalInterface
interface Operacion {
int ejecutar(int a, int b);
}
// FORMA TRADICIONAL (clase anónima)Operacion suma = new Operacion() {
@Override
public int ejecutar(int a, int b) {
return a + b;
}
};
// FORMA LAMBDA (equivalente)Operacion suma = (a, b) -> a + b;
Lambda Lab
Common Functional Interfaces
Represents a function that takes one argument and returns boolean
Predicate esLargo = s -> s.length() > 10;
Takes one argument and produces a result
Function longitud = s -> s.length();
Performs an operation with the argument (without returning)
Consumer imprimir = s -> System.out.println(s);
Provides/supplies a result (without receiving arguments)
Supplier random = () -> Math.random();
Streams API
Declarative Processing of Collections
Source
Create a Stream from a collection
List lista = Arrays.asList("a", "b", "c");
Stream stream = lista.stream();
Intermediate Operations
Transform or filter elements
stream.filter(s -> s.startsWith("a"))
.map(String::toUpperCase);
Terminal Operation
Get the final result
List resultado = stream.collect(Collectors.toList());
Streams Simulator
Input Data (comma-separated):
Intermediate Operations:
Terminal Operation:
Original Source
Intermediate Operations
Final Result
Practical Stream Examples
Filter and Transform
List nombres = Arrays.asList("Ana", "Juan", "María");
List resultado = nombres.stream()
.filter(n -> n.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
// Result: ["MARÍA"]
Numeric Operations
List numeros = Arrays.asList(1, 2, 3, 4, 5);
int suma = numeros.stream()
.mapToInt(Integer::intValue)
.sum();
// Result: 15
Grouping
List palabras = Arrays.asList("java", "python", "java", "c++");
Map conteo = palabras.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
// Result: {java=2, python=1, c++=1}
Dates and Times (Java 8+)
Modern Dates API (java.time)
Old (java.util.Date) - ❌ NOT RECOMMENDED
Date fecha = new Date(); // MutabilidadCalendar cal = Calendar.getInstance();
cal.set(2024, 0, 1); // Enero es 0Date añoNuevo = cal.getTime();
Mutability (not thread-safe)
Confusing API (months from 0 to 11)
No default time zone
Modern (java.time) - ✅ RECOMMENDED
LocalDate hoy = LocalDate.now(); // ImmutabilityLocalDate añoNuevo = LocalDate.of(2024, 1, 1);
LocalTime ahora = LocalTime.now();
LocalDateTime fechaHora = LocalDateTime.now();
Immutability (thread-safe)
Clear and consistent API
Built-in time zones
Dates Lab
LocalDate
LocalTime
LocalDateTime
ZonedDateTime
Date Formatting and Parsing
From String to Date
// Parseo de fechaDateTimeFormatter formatter =
DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate fecha = LocalDate.parse("15/01/2024", formatter);
From Date to String
// Formateo de fechaLocalDate hoy = LocalDate.now();
String formato = hoy.format(
DateTimeFormatter.ofPattern("EEEE dd 'de' MMMM 'de' yyyy")
);
// Result: "lunes 15 de enero de 2024"
Duration and Period
// Diferencia entre fechasLocalDate inicio = LocalDate.of(2024, 1, 1);
LocalDate fin = LocalDate.of(2024, 12, 31);
Period periodo = Period.between(inicio, fin);
// Result: P11M30D (11 months, 30 days)
File Handling
Efficient Reading and Writing
Basic Reading (FileReader)
// Lectura básica (poco eficiente)FileReader fr = new FileReader("archivo.txt");
int caracter;
while ((caracter = fr.read()) != -1) {
System.out.print((char) caracter);
}
fr.close();
Character-by-character reading
Not buffered
Efficient Reading (BufferedReader)
// Lectura eficiente con bufferBufferedReader br = new BufferedReader(
new FileReader("archivo.txt")
);
String linea;
while ((linea = br.readLine()) != null) {
System.out.println(linea);
}
br.close();
Buffered (high performance)
Line-by-line reading
Modern Reading (Java 7+)
// try-with-resources (auto-close)
try (BufferedReader br = Files.newBufferedReader(
Paths.get("archivo.txt")
)) {
br.lines().forEach(System.out::println);
} // No necesita close() explícito
Auto-closeable
Uses Streams
Virtual File Editor
Virtual File Content
Write New Content
Append to End of File
File Operations:
Practical Examples
Read CSV File
// Leer y procesar archivo CSVtry (BufferedReader br = Files.newBufferedReader(
Paths.get("datos.csv")
)) {
br.lines()
.skip(1) // Saltar cabecera .map(linea -> linea.split(","))
.filter(campos -> campos.length == 3)
.forEach(campos -> {
String nombre = campos[0];
int edad = Integer.parseInt(campos[1]);
String ciudad = campos[2];
// Procesar datos... });
}
Write Log File
// Escribir archivo de logtry (BufferedWriter bw = Files.newBufferedWriter(
Paths.get("app.log"),
StandardOpenOption.CREATE,
StandardOpenOption.APPEND
)) {
LocalDateTime ahora = LocalDateTime.now();
String mensaje = String.format(
"[%s] %s: %s%n",
ahora.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
"INFO",
"Aplicación iniciada correctamente"
);
bw.write(mensaje);
}
Copy File
// Copiar archivo eficientementePath origen = Paths.get("original.txt");
Path destino = Paths.get("copia.txt");
try (InputStream in = Files.newInputStream(origen);
OutputStream out = Files.newOutputStream(destino)) {
byte[] buffer = new byte[1024];
int bytesLeidos;
while ((bytesLeidos = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesLeidos);
}
}
Integrated Exercises
Inventory System with Generics
Create an inventory system that uses generics to handle different product types:
- Generic class
Almacen<T>that stores products of type T - Interface
Productowith methodsgetPrecio()andgetNombre() - Classes
ProductoFisicoandProductoDigitalthat implement Producto - Generic method to calculate the total inventory value
- Use of wildcards for methods that read products
Text Processor with Lambdas and Streams
Implement a text processor that uses lambdas and streams for text analysis:
- Read text file using
Files.lines() - Use lambdas to filter, transform and reduce
- Calculate statistics: most common words, average length
- Generate a formatted report using dates
- Write results to a file using
BufferedWriter
Event Manager with Dates API
Create a system to manage events using the modern dates API:
- Class
Eventowith name, date/time and duration - Use
LocalDateTimeandDuration - Filter events by date using lambdas
- Calculate remaining time for future events
- Sort events chronologically using streams
- Export schedule to CSV file
Advanced Logging System
Implement a logging system that combines all the advanced features:
- Generic class
Logger<T>for different message types - Use lambdas for custom message formatting
- Streams for log analysis (error frequency, etc.)
- Dates API for each entry's timestamp
- Log file rotation by date
- Efficient log search using parallel streams
Advanced Concepts Quiz
Question 1: What is the main advantage generics offer in Java?
Summary and Resources
What You Learned in This Module
Generics
- Parameterized classes and methods
- Compile-time type safety
- Wildcards: extends, super, unbounded
- Eliminate the need for explicit casts
Lambda Expressions
- Concise syntax for functional interfaces
- Functional programming in Java
- Common interfaces: Predicate, Function, Consumer, Supplier
- Method references (::)
Streams API
- Declarative processing of collections
- Intermediate and terminal operations
- Processing pipelines
- Parallel streams for concurrent processing
Dates and Times
- API java.time (immutable and thread-safe)
- LocalDate, LocalTime, LocalDateTime
- ZonedDateTime for time zones
- Period and Duration for calculations
File Handling
- Efficient reading/writing with buffers
- Try-with-resources for auto-close
- NIO.2 for modern file operations
- File processing with streams