Functional Programming


What is Functional Programming?

Functional Programming (FP) is a programming style where you write programs by building functions that perform computations. Instead of focusing on how to solve a problem (step-by-step instructions), you focus on what result you want.

Definition: Functional Programming is a way of coding where you avoid changing state and use pure functions to describe what should happen. 

🔹 Key Concepts of Functional Programming


Description

Java Example

Functions as first-class citizens

Functions can be assigned to variables, passed as arguments, or returned from other functions

Function<String, Integer> f = s -> s.length();

Pure Functions

Given the same input, always return the same output. No side effects

x -> x * 2

Immutability

Data is not changed. New copies are created with updated values

List<String> result = list.stream().filter(...)

Declarative Style

Focus on what to do, not how to do it

list.stream().filter(x -> x > 5)

Higher-Order Functions

Functions that accept or return other functions

map(), filter() in Streams

Lazy Evaluation

Execution is deferred until needed

Stream.generate(() -> Math.random())

Recursion

Replacing traditional loops with recursive function calls

Used in functional-style programming


🔹 Brief History of Functional Programming

  • 1950s – Introduced with LISP, one of the first FP languages.
  • 1970s–90s – Languages like Haskell and Scala promoted pure FP.
  • 2000s–present – Mainstream languages (Java, JavaScript, Python) adopted FP features.


🔹 Functional Programming in Java (Since Java 8)

Java began supporting Functional Programming with Java 8, bringing:
  • Lambda Expressions – Anonymous functions for cleaner, inline code.
  • Functional Interfaces – Interfaces with a single abstract method (e.g., Predicate, Function).
  • Streams API – Declarative data processing pipelines.


🔹 Why Use Functional Programming in Java?


Benefit

Description

Easier to test/debug

Pure functions are predictable and isolated

Thread-safe

No shared state; ideal for concurrency

Reusable & modular

Code is divided into small, composable units

Clean syntax

Reduces boilerplate, improves readability



🔹 Real-Life Use Cases of Functional Programming 


Use Case

Example

Data Processing

Filtering and transforming lists using stream().filter()

Concurrency

Immutable objects in parallel streams

Event-driven Systems

Lambdas as callbacks

Functional Pipelines

map(), filter(), reduce() operations


🔹 Example: Funcational Programming

//Filter even numbers using streams

import java.util.*; import java.util.stream.*; public class FPExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) // Lambda .collect(Collectors.toList()); System.out.println(evenNumbers); // Output: [2, 4] } }

What is Lambda Expression?

A Lambda Expression is a concise way to represent an anonymous function (a block of code with inputs and outputs but no name).

Lambda helps enable Functional Programming by simplifying the use of functional interfaces.

🔹 Syntax of Lambda Expression

(parameters) -> { body }
  • Curly braces {} can be omitted for single-line expressions.

  • Type declarations are usually inferred.


🔹 Example: Before and After Lambda

    Without Lambda (Old Way):

    Runnable r = new Runnable() {     public void run() {     System.out.println("Running in old way");     }     };     r.run();

    With Lambda (Modern Way):

    Runnable r = () -> System.out.println("Running with Lambda");     r.run();

🔹 Advantages of Lambda Expressions


Benefit

Description

Less Code

No need for anonymous inner classes

More Readable

Focuses on logic instead of boilerplate

Enables FP

Works seamlessly with Streams, Collections, etc.

Enables Concurrency

Fits well with parallel operations and callback structures



What is Method Reference?
Method Reference is a shorthand for lambda expressions that just call an existing method.
It's more concise, readable, and avoids boilerplate.

Lambda vs Method Reference — At a Glance

Lambda Expression

Equivalent Method Reference

x -> System.out.println(x)

System.out::println

(a, b) -> Math.max(a, b)

Math::max

str -> str.toUpperCase()

String::toUpperCase

() -> new ArrayList<>()

ArrayList::new


Types of Method References

Type

Syntax

Example

Static method

Class::staticMethod

Math::abs

Instance method of object

obj::instanceMethod

System.out::println

Instance method of class type

Class::instanceMethod

String::toLowerCase

Constructor

Class::new

ArrayList::new


Example: Lambda vs Method Reference

import java.util.*;

import java.util.function.*;


public class MethodReferenceComparison {

    public static void main(String[] args) {

        List<String> names = Arrays.asList("Java", "Python", "Go");


        // Lambda: prints each name

        names.forEach(name -> System.out.println(name));


        // Method Reference (same as above)

        names.forEach(System.out::println);


        // Lambda: convert to upper case

        List<String> upper = names.stream()

                                  .map(name -> name.toUpperCase())

                                  .toList();


        // Method Reference

        List<String> upper2 = names.stream()

                                   .map(String::toUpperCase)

                                   .toList();


        // Static method reference (Math.max)

        BiFunction<Integer, Integer, Integer> lambdaMax = (a, b) -> Math.max(a, b);

        BiFunction<Integer, Integer, Integer> refMax = Math::max;

        System.out.println("Lambda Max: " + lambdaMax.apply(10, 20));

        System.out.println("Ref Max: " + refMax.apply(10, 20));


        // Constructor reference

        Supplier<ArrayList<String>> lambdaList = () -> new ArrayList<>();

        Supplier<ArrayList<String>> refList = ArrayList::new;

        System.out.println("List created using constructor ref: " + refList.get());

    }

}

Output

Java

Python

Go

Lambda Max: 20

Ref Max: 20

List created using constructor ref: []


Summary Method Reference

  • Use Lambda when logic is custom or short-lived.
  • Use Method Reference when reusing existing methods.
  • Both are interchangeable in many cases but method references are cleaner when applicable.



What is a Functional Interface?

A Functional Interface is an interface with exactly one abstract method, which makes it suitable for lambda expressions or method references.

🔹 Example: Custom Functional Interface

@FunctionalInterface interface Calculator { int calculate(int a, int b); } public class CustomFunctionalInterface { public static void main(String[] args) { Calculator add = (a, b) -> a + b; Calculator multiply = (a, b) -> a * b; System.out.println(add.calculate(4, 5)); // 9 System.out.println(multiply.calculate(4, 5)); // 20 } }

Note: The @FunctionalInterface annotation is optional but recommended. It ensures the interface contains only one abstract method.

 

🔹 Built-in Functional Interfaces in Java

Java provides many pre-defined functional interfaces in the java.util.function package:

Interface

Input

Output

Example

Predicate<T>

T

boolean

x -> x > 10

Function<T, R>

T

R

x -> x + 1

Consumer<T>

T

void

x -> System.out.println(x)

Supplier<T>

none

T

() -> "Hello"

BinaryOperator<T>

T, T

T

(a, b) -> a * b


🔹 Example: Built-in Functional Interfaces

import java.util.function.*; public class BuiltInFunctionalInterfacesDemo { public static void main(String[] args) { Predicate<Integer> isEven = n -> n % 2 == 0; Function<String, Integer> strLength = s -> s.length(); Consumer<String> greet = name -> System.out.println("Hello, " + name + "!"); Supplier<Double> random = () -> Math.random(); System.out.println("Is 10 even? " + isEven.test(10)); // true System.out.println("Length of 'Java': " + strLength.apply("Java")); // 4 greet.accept("Siraj"); // Hello, Siraj! System.out.println("Random number: " + random.get()); } }

🔹 Final Summary


Topic

Summary

Functional Programming

Focuses on what to solve using pure functions and immutable data

Lambda Expressions

Anonymous, concise functions ((a, b) -> a + b)

Functional Interface

Interface with one method; enables lambda usage

Streams API

Declarative data processing using map(), filter(), collect()

Benefits

Modular, thread-safe, testable, readable, and expressive code

Advanced Concepts

Higher-order functions, recursion, lazy evaluation, function composition