Functional Interfaces
Functional interfaces are single-method interfaces used primarily in lambda expressions and method references. Some common functional interfaces include:
-
Supplier: Represents a function with no arguments that returns a value.
Supplier
supplier = () -> "Hello, World!"; System.out.println(supplier.get()); // Output: Hello, World! -
Consumer: Represents a function with one argument that performs an action but does not return a value.
Consumer
consumer = x -> System.out.println("Value: " + x); consumer.accept(42); // Output: Value: 42 -
Function: Represents a function with one argument that produces a result.
Function
function = x -> "Number: " + x; System.out.println(function.apply(10)); // Output: Number: 10 -
Predicate: Represents a function with one argument that returns a boolean value.
Predicate
predicate = str -> str.length() > 5; System.out.println(predicate.test("Java")); // Output: false System.out.println(predicate.test("Functional")); // Output: true
Working with Optional
The Optional
class is used to represent optional values that may or may not be present.
-
Creating an
Optional
:Optional
optional = Optional.of("Hello"); Optional emptyOptional = Optional.empty(); -
Accessing an
Optional
:optional.ifPresent(System.out::println); // Output: Hello System.out.println(optional.orElse("Default Value")); // Output: Hello
Understanding Stream Operations
Streams allow for functional-style operations on collections and other data sources. They are executed lazily, meaning intermediate operations do not execute until a terminal operation is encountered.
-
Intermediate Operations: These are operations that transform a stream and return another stream. Examples include:
filter()
: Filters elements based on a condition.List
numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.stream() .filter(x -> x % 2 == 0) .forEach(System.out::println); // Output: 2, 4 map()
: Transforms each element.List
names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream() .map(String::toUpperCase) .forEach(System.out::println); // Output: ALICE, BOB, CHARLIE
-
Terminal Operations: These trigger the execution of the stream pipeline. Examples include:
collect()
: Gathers elements into a collection.List
collected = numbers.stream() .filter(x -> x > 2) .collect(Collectors.toList()); System.out.println(collected); // Output: [3, 4, 5] reduce()
: Combines elements into a single value.int sum = numbers.stream() .reduce(0, Integer::sum); System.out.println(sum); // Output: 15
Primitive Streams
Java provides primitive stream types to handle specific data types efficiently:
IntStream
: For int values.DoubleStream
: For double values.LongStream
: For long values.
IntStream.range(1, 5)
.forEach(System.out::println); // Output: 1, 2, 3, 4
Using Method References and Lambdas
Method references are a shorthand for lambdas that only call a method:
// Using a lambda
list.forEach(x -> System.out.println(x));
// Using a method reference
list.forEach(System.out::println);
Sorting and Searching a Stream
-
Sorting: The
sorted()
method sorts elements in natural or custom order.List
sorted = numbers.stream() .sorted() .collect(Collectors.toList()); System.out.println(sorted); // Output: [1, 2, 3, 4, 5] -
Searching: Use
findFirst()
,findAny()
, or matching methods to locate elements.Optional
firstEven = numbers.stream() .filter(x -> x % 2 == 0) .findFirst(); System.out.println(firstEven.get()); // Output: 2
0 Comments