DEV Community

DevCorner
DevCorner

Posted on

Functional Programming in Java

Your blog on Functional Programming in Java should cover the following topics in detail:


1. Lambda Expressions & Method References

Lambda Expressions in Java

Lambda expressions were introduced in Java 8 to provide a concise way to represent anonymous functions. They are mainly used in functional programming and the Streams API.

Syntax of Lambda Expressions

(parameters) -> expression
Enter fullscreen mode Exit fullscreen mode

or

(parameters) -> { statements }
Enter fullscreen mode Exit fullscreen mode

Example: Lambda Expression in Action

// Traditional Anonymous Class Implementation
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from Anonymous class!");
    }
};

// Using Lambda Expression
Runnable r2 = () -> System.out.println("Hello from Lambda Expression!");

r1.run();
r2.run();
Enter fullscreen mode Exit fullscreen mode

Key Features of Lambda Expressions

  • Eliminates boilerplate code (No need for anonymous class)
  • Concise & readable
  • Can be passed as an argument to higher-order functions
  • Used with functional interfaces

Method References in Java

A method reference is a shorthand for writing lambda expressions when the lambda only calls an existing method.

Types of Method References

Type Syntax Example
Reference to a Static Method ClassName::staticMethod Math::sqrt
Reference to an Instance Method objectRef::instanceMethod System.out::println
Reference to an Instance Method of an Arbitrary Object ClassName::instanceMethod String::length
Reference to a Constructor ClassName::new ArrayList::new

Example: Method References vs Lambda Expressions

import java.util.function.Function;

public class MethodRefExample {
    public static void main(String[] args) {
        // Using Lambda Expression
        Function<String, Integer> lambdaFunction = (str) -> str.length();

        // Using Method Reference
        Function<String, Integer> methodRefFunction = String::length;

        System.out.println(lambdaFunction.apply("Java"));  // Output: 4
        System.out.println(methodRefFunction.apply("Method Reference")); // Output: 16
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Streams API & Parallel Streams

What is the Streams API?

  • Introduced in Java 8, the Streams API provides a functional-style approach to processing collections of data.
  • It allows declarative, parallel, and lazy execution of operations.

Example: Using Streams

import java.util.Arrays;
import java.util.List;

public class StreamsExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("John", "Jane", "Jack", "Jill");

        // Using Stream to filter and print names that start with 'J'
        names.stream()
             .filter(name -> name.startsWith("J"))
             .forEach(System.out::println);
    }
}
Enter fullscreen mode Exit fullscreen mode

Parallel Streams in Java

  • Parallel streams allow operations to run in parallel using multiple threads.
  • Uses ForkJoin framework internally to process collections concurrently.

Example: Parallel Stream vs. Sequential Stream

import java.util.stream.IntStream;

public class ParallelStreamExample {
    public static void main(String[] args) {
        System.out.println("Sequential Stream:");
        long start = System.currentTimeMillis();
        IntStream.range(1, 10).forEach(System.out::println);
        long end = System.currentTimeMillis();
        System.out.println("Time taken: " + (end - start) + " ms");

        System.out.println("\nParallel Stream:");
        start = System.currentTimeMillis();
        IntStream.range(1, 10).parallel().forEach(System.out::println);
        end = System.currentTimeMillis();
        System.out.println("Time taken: " + (end - start) + " ms");
    }
}
Enter fullscreen mode Exit fullscreen mode

When to Use Parallel Streams?

✅ Use when:

  • You are dealing with large data sets.
  • The operations are independent and can run concurrently.

❌ Avoid when:

  • Tasks are small and involve I/O operations (as thread switching may add overhead).

3. Collectors & Functional Interfaces

What are Collectors?

Collectors are utility methods in the java.util.stream.Collectors class, used to accumulate elements from a stream into a data structure.

Example: Collecting Stream Results

import java.util.List;
import java.util.stream.Collectors;
import java.util.Arrays;

public class CollectorsExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

        // Collecting names into a List
        List<String> filteredNames = names.stream()
                                          .filter(name -> name.startsWith("A"))
                                          .collect(Collectors.toList());

        System.out.println(filteredNames); // Output: [Alice]
    }
}
Enter fullscreen mode Exit fullscreen mode

Common Collector Methods

Collector Method Description
toList() Collects stream elements into a List.
toSet() Collects elements into a Set (removes duplicates).
toMap() Collects elements into a Map.
joining() Concatenates elements into a String.
groupingBy() Groups elements by a classifier function.
partitioningBy() Partitions elements into two groups (true/false condition).

What are Functional Interfaces?

A functional interface is an interface that contains only one abstract method. They are used extensively in lambda expressions.

Common Functional Interfaces in Java

Interface Method Description
Predicate<T> boolean test(T t) Represents a boolean condition.
Function<T, R> R apply(T t) Converts T to R.
Consumer<T> void accept(T t) Performs an operation on T without returning a value.
Supplier<T> T get() Provides an object without input.
BiFunction<T, U, R> R apply(T t, U u) Takes two inputs and returns a result.

Example: Using Functional Interfaces

import java.util.function.Function;
import java.util.function.Predicate;

public class FunctionalInterfaceExample {
    public static void main(String[] args) {
        // Predicate: Check if a number is even
        Predicate<Integer> isEven = (num) -> num % 2 == 0;
        System.out.println(isEven.test(10)); // Output: true

        // Function: Convert a String to Upper Case
        Function<String, String> toUpperCase = String::toUpperCase;
        System.out.println(toUpperCase.apply("hello")); // Output: HELLO
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Functional programming in Java using Lambda Expressions, Method References, Streams API, Parallel Streams, Collectors, and Functional Interfaces helps write cleaner and more concise code. These concepts improve performance and simplify operations in Java applications.

Would you like me to add more examples, interview questions, or use cases for enterprise applications? 🚀

Top comments (0)