Functional Interfaces and Streams in Java

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
                    

Post a Comment

0 Comments