Java 8 introduced the Streams API and functional programming features like lambdas and method references. These features enable you to write more concise, readable, and expressive code. This tutorial will guide you through the basics of the Streams API, lambda expressions, and method references, and how to use them effectively in your Java programs.
Java Streams API and Functional Programming Tutorial
By the end of this tutorial, you'll understand how to leverage functional programming concepts and the Streams API to process collections of data in a declarative and efficient manner.
What is Functional Programming?
Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data. In Java, functional programming is supported through:
- Lambda Expressions: Anonymous functions that can be passed around as values.
- Method References: Shorthand syntax for referring to methods by their names.
- Functional Interfaces: Interfaces with a single abstract method (SAM).
Lambda Expressions
Lambda expressions provide a clear and concise way to represent instances of functional interfaces.
- Syntax:
(parameters) -> expression (parameters) -> { statements; }
- Example:
// Without lambda Runnable r1 = new Runnable() { public void run() { System.out.println("Hello, World!"); } }; // With lambda Runnable r2 = () -> System.out.println("Hello, World!"); r1.run(); r2.run();
Method References
Method references provide a shorthand syntax for calling methods by their names.
- Types of Method References:
- Static Method:
ClassName::staticMethodName
- Instance Method:
instance::methodName
- Constructor:
ClassName::new
- Static Method:
- Example:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // Using lambda names.forEach(name -> System.out.println(name)); // Using method reference names.forEach(System.out::println);
Functional Interfaces
Functional interfaces are interfaces with a single abstract method (SAM). Java provides several built-in functional interfaces in the java.util.function
package.
- Common Functional Interfaces:
Predicate<T>
: Represents a boolean-valued function.Function<T, R>
: Represents a function that takes one argument and produces a result.Consumer<T>
: Represents an operation that takes a single input and returns no result.Supplier<T>
: Represents a supplier of results.
- Example:
Predicate<String> isLong = s -> s.length() > 5; System.out.println(isLong.test("Hello")); // false Function<String, Integer> lengthFunction = String::length; System.out.println(lengthFunction.apply("Hello")); // 5 Consumer<String> printConsumer = System.out::println; printConsumer.accept("Hello, World!"); Supplier<String> stringSupplier = () -> "Hello"; System.out.println(stringSupplier.get()); // Hello
Streams API
The Streams API provides a powerful way to process sequences of elements, such as collections, in a functional style.
- Key Features:
- Intermediate Operations: Transform a stream into another stream (e.g.,
filter
,map
). - Terminal Operations: Produce a result or side-effect (e.g.,
forEach
,collect
). - Lazy Evaluation: Intermediate operations are not executed until a terminal operation is invoked.
- Intermediate Operations: Transform a stream into another stream (e.g.,
- Example:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // Filter names starting with 'A' and convert to uppercase List<String> result = names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(result); // [ALICE]
Common Stream Operations
Here are some common operations you can perform with the Streams API:
- Filter: Select elements that match a condition.
- Map: Transform elements using a function.
- Reduce: Combine elements into a single result.
- Collect: Gather elements into a collection.
- Sort: Sort elements based on a comparator.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Sum of even numbers
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.reduce(0, Integer::sum);
System.out.println("Sum: " + sum); // Sum: 6
This tutorial covered the basics of the Streams API and functional programming in Java. Practice using these concepts to write more expressive and efficient code.