Functional Style Programming in java

Shankar Ghimire
4 min readSep 6, 2020

--

Though functional programming’s concept is introduced back in the 1930s with lambda calculus before the object-oriented programming paradigm, its popularity it begins late. The main reason for its popularity is due to a need for horizontal scaling for distributed computing. This means that more cores per processor are being used, instead of faster processors. Besides this functional programming has a lot of pros.

What is functional programming?

It is a programming paradigm in which the program is constructed through functional composition. Functional programming treat’s function as the first-class citizen that means you can

  • pass a function to function
  • create a function within a function
  • return function from the function

Java is not a functional programming language but it supports some functional features, like lambda, lazy evaluation. However, doesn’t strictly enforce immutability. So we called this a functional style language. (support functional feature in the object-oriented paradigm)

Comparing it with imperative programming in which statements change the program state.

Imperative vs functional comparison

Imperative Style:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
int result = 0; //mutable state
for (int i = 0; i < numbers.size(); i++) { //external iterator
result += numbers.get(i);
}
System.out.println("result = " + result);

Functional style:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
int result = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("result = " + result);

In the above examples, the imperative style is more focused on how to sum these numbers. It creates a mutable variable result, uses an external iterator to add all the numbers. These two actions are more error-prone as different types of collection may have different ways to iterate over and get value.

Higher-order function

A higher-order function is a function that takes a function as an argument or returns a function.

Mathematically

h(x) = g(f(x))

In java 8 we can write a functional composition as:

Function<Integer, Double> f = x-> x* 2.0;
Function<Double, BigDecimal> g = x-> new BigDecimal(x);
Function<Integer, BigDecimal> hx = g.compose(f);

Like Function, other functional interfaces make it easy for functional composition. some of them are consumer, supplier, predicate.

Consumer

Input → it consumes inputs only, does not return anything.

T → { consume input here}

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Consumer<List<Integer>> printInteger = System.out::println;
printInteger.accept(numbers);

Supplier

It takes no input but returns the value.

( ) → R (return value)

Supplier<Double> randomValueSupplier = () -> Math.random();randomValueSupplier.get();

Predicate

It takes an input value and is required to return boolean as an output.

T R (Boolean value)

Predicate<String> nullOrEmpty = e -> e == null || e.isEmpty();
nullOrEmpty.test("hello");

Besides these, When the above function interface does not fulfill your criteria. you can define your functional interface. This interface must contain only a single abstract (unimplemented) method.

@FunctionalInterface
public interface AreaService {
int calculate(int l, int b);}//use this as
AreaService rectangleArea = (l, b) -> l * b;
rectangleArea.calculate(4,5);

Pure function

Function with no side effects.

  • The function does not change anything.
  • Does not depend upon anything that changes. (lazy evaluation function)

The first point emphasizes immutability, Immutability is the heart of pure function. Rather than changing state functional programming emphasize on transferring the state. Mutability might not be a problem in most of the cases but shared mutability is dangerous. It might behave unexpectedly if we execute a program in a multithreaded environment.

The second point, if function depends upon change then the lazy evaluation will not possible, and laziness is another important property pure functional language.

Lazy evaluation

The function can be executed now, late, or never. In imperative programming, functions are executed immediately. This is not something good for performance. A performant function is a function that never executes. The important thing here is you cannot have a lazy evaluation with mutability.

Example:

Stream.iterate(1, i -> i + 1)
.filter(e -> e % 2 == 0) //Intermediate operation, lazy
.mapToInt(Integer::intValue) //Intermediate operation, lazy
.limit(100) //Intermediate operation, lazy
.sum(); //terminal operation, strict

All of the stream operations can be divided into intermediate operation and terminal operation. Map, filter, peek are intermediate operation they produce stream whereas, forEach, collect, sum, count are terminal operations. Terminal operations produce either value or side-effect. All the intermediate operations are lazy.

In the above example, Though Stream.iterate is generating an infinite stream limit(100) act’s as a short-circuit operation and produces a finite stream of 100 numbers.

Keynote:

  • don’t mutate state rater transfer the state.
  • Avoid shared mutable state.
  • Lazy evaluation will improve performance.
  • Impure functions are more error-prone.
  • Easier to make code run parallel for pure function.

--

--

Shankar Ghimire
Shankar Ghimire

Written by Shankar Ghimire

Software engineer. data enthusiastic.

No responses yet