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 or (parameters) -> { statements } 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(); 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 lambdaFunction = (str) -> str.length(); // Using Method Reference Function methodRefFunction = String::length; System.out.println(lambdaFunction.apply("Java")); // Output: 4 System.out.println(methodRefFunction.apply("Method Reference")); // Output: 16 } } 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 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); } } 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"); } } 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 names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // Collecting names into a List List filteredNames = names.stream() .filter(name -> name.startsWith("A")) .collect(Collectors.toList()); System.out.println(filteredNames); // Output: [Alice] } } Common Collector Methods Collector Method Description toList() Collects stream elements into a List. toSet() Collects elements into a Set (removes duplicates).

Mar 7, 2025 - 03:46
 0
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

or

(parameters) -> { statements }

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();

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
    }
}

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);
    }
}

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");
    }
}

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]
    }
}

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 boolean test(T t) Represents a boolean condition.
Function R apply(T t) Converts T to R.
Consumer void accept(T t) Performs an operation on T without returning a value.
Supplier T get() Provides an object without input.
BiFunction 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
    }
}

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?