Functional Programming Using Vavr In Java

Introduction

Vavr is a functional library designed especially for Java, it is very much like Scala. Vavr library has functional programming paradigms like Monads, Function Currying, Partial Functions, and the data-structures in Vavr are all Immutable. Vavr features can turn Java into a pure Functional Programming language. In this article, we will explore some of the Vavr features,

  1. Tuple
  2. Option Monad
  3. Try (Big Try)
  4. Function Currying
  5. Lazy

 Let’s explore.

Tuple

The Tuple data structure doesn’t exist in Java. Tuple is a collection of heterogeneous elements means multiple data types can be combined, tuples are immutable in nature. Tuple in Vavr is not flexible as it’s in Python to store 2 different elements. ‘Tuple2’ should be used for 3 elements. Tuple3, there is an upper limit of 8 elements in Vavr.  

Just like in Scala tuple elements can be accessed like ._1, ._2, and so on.

Tuple2<String, Integer> tuple = Tuple.of("David", 50);
System.out.println(tuple._1); //David
System.out.println(tuple._2); //50

Tuples can transform using the map function. 

Tuple2<String, Integer> modifiedTuple = tuple.map(s -> s.toUpperCase(), a -> a);
System.out.println(modifiedTuple._1); //DAVID

Option Monad

Option Monad in Vavr is like Java 8’s Optional. Vavr’s Option is very much like Scala’s Option which represents the presence and absence of values using ‘Some’ and ‘None’.

Functional Programming using Vavr in Java

Option<String> option = Option.of("David");
System.out.println(option.map(x -> x.toUpperCase())); // Some(David)
		
Option<String> option1 = Option.of(null);
System.out.println(option1.map(x -> x.toUpperCase())); //None

The Option class in Vavr has a collection of some extra methods than Java’s Optional, some of them are

  1. peek
  2. isLazy
  3. isDefined

Try

Try in Vavr is a type that represents a computation that can result in the exception or return computed value successfully. In short by using Try throws can be processed functionally, Try returns either ‘Success’  or ‘Failure’

Functional Programming using Vavr in Java

Code flow using Try looks like,

Try.of(() -> functionCall())
.onSuccess(result -> result)
.onFailure(error -> error)

Failure Scenario

private static double calculate(Integer value) {
    return value / 0;
}
public static void main(String[] args) {
    Try.of(() - > calculate(20)).map(result - > result + 1).onSuccess(comp - > System.out.println("Comp:" + comp)).onFailure(error - > System.out.println("Error:" + error));
}

Output

Error:java.lang.ArithmeticException: / by zero

Success Scenario

private static double calculate(Integer value) {
    return value / 1;
}
public static void main(String[] args) {
    Try.of(() - > calculate(20)).map(result - > result + 1).onSuccess(comp - > System.out.println("Comp:" + comp)).onFailure(error - > System.out.println("Error:" + error));
}

Output

"Comp:" 21.0

Function Currying

Function Currying is a technique of applying a function partially by fixing the value of some of the parameters, Vavr supports functions up to 8 parameters.

Function2<String, String, String> email = (x, y) -> y + x;
Function1<String, String> email_pf = email.curried().apply("@gmail.com");
System.out.println(email_pf.curried().apply("David"));  //David@gmail.com

The email function is adding two parameters, in the second function “@gmail.com” is fixed and we applied the currying on two functions where one has a fixed value and final value can vary.

Lazy

Lazy is also a monad, which represents a value that Lazily evaluated, meaning the computation is deferred until the result is absolutely required. The returned value is cached or memorized.

private static int getRandomValue() {
    Random random = new Random();
    return random.nextInt(100);
}
public static void main(String[] args) {
    Lazy < Integer > lazy = Lazy.of(() - > getRandomValue());
    System.out.println(lazy.isEvaluated()); //false
    System.out.println(lazy.get()); //96 
    System.out.println(lazy.isEvaluated()); //true
    System.out.println(lazy.get()); //96
}

The first ".isEvaluated()" returns false because the Lazy is not executed, In first ".get()" random is generated, Second  "isEvaluated" is true because Lazy is executed, the last ".get()" return the Memoized Value.

Summary

Vavr is simple to use and features can be implemented with basic functional knowledge, but if you decide to use Vavr then I highly recommend going through functional programming concepts then Vavr will make more sense to you.