Java Functional Programming & Pattern Matching With VAVR

Emre Savcı
Apr 14 · 3 min read

Vavr (formerly called Javaslang) is a functional library for Java 8+ that provides persistent data types and functional control structures.

As it already stated in their user guide, in this blog we will use VAVR to implement functional programming in java. The library has many useful data structures including Lazy, Option etc. Also it is fully compatible with plain java.

  • Lazy Type

In vavr we can create lazy evaluated values.

Lazy<Double> lazy = Lazy.of(Math::random);
lazy.isEvaluated(); // = false
lazy.get(); // = 0.123 (random generated)
lazy.isEvaluated(); // = true
lazy.get(); // = 0.123 (memoized)

We can aslo create real lazy value:

CharSequence chars = Lazy.val(() -> "Yay!", CharSequence.class);
System.out.println(chars.charAt(0)); // Y

  • Vavr List Has Some Capabilites
String stringWithComma = List.of("1","2","3")
.intersperse(",")
.foldLeft(new StringBuilder(), StringBuilder::append)
.toString();
System.out.println(stringWithComma);

It prints us to "1,2,3".

We can convert Vavr List to Java List:

List.of("1","2","3").asJava();

We can find combinations:

System.out.println(List.of(1,2,3).combinations());//output:List(List(), List(1), List(2), List(3), List(1, 2), List(1, 3), List(2, 3), List(1, 2, 3))

Or we can find distinct elements:

System.out.println(List.of(1,2,3,3,4,4).distinct());//output:List(1, 2, 3, 4)
  • Tuples
public static void main(String[] args) {
Tuple2<Integer, Integer> tuple = Tuple.of(1,2);

System.out.println(tuple._2);
}
// 2orTuple3 tuple = Tuple.of(1,2,3);
System.out.println(tuple._3);
// 3

  • Method Chaining

Using Vavr’s Function types, we can chain methods together using andThen methods.

public class Main {

public static void main(String[] args) {
Function3 calculationMethodFunction = Function3.of(Main::calculationMethod);

calculationMethodFunction.andThen(x -> {
System.out.println("first result: " + x);
return 2 * (int)x;
}).andThen(x -> {
System.out.println("second result: " + x);
return x;
}).apply(1,2,3);
}

public static int calculationMethod(int a, int b, int c) {
System.out.println("calculation method called");
return a + b + c;
}
}

Or better, we can memoize existing methods.

  • Method Memoization
public class Main {

public static void main(String[] args) {
Function3 calculationMethodFunction = Function3.of(Main::calculationMethod);

Function3 memoizedCalculationMethodFunction = calculationMethodFunction.memoized();
int firstResult = (int)memoizedCalculationMethodFunction.apply(1,2,3);

int secondResult = (int)memoizedCalculationMethodFunction.apply(1,2,3);

System.out.println(firstResult);
System.out.println(secondResult);
}

public static int calculationMethod(int a, int b, int c) {
System.out.println("calculation method called");
return a + b + c;
}
}

In Vavr we have pattern matching.

  • Pattern Matching
public static void main(String[] args) {

int i = 5;

String s = Match(i).of(
Case($(1), "one"),
Case($(2), "two"),
Case($(), "unkown number")
);

System.out.println(s);
}

The output is obvious: "unknown number".

Another things can be done with pattern matching:

public class Main {

public static void main(String[] args) {

String result = "some string";

Match(result).of(
Case($("first"), o -> run(Main::first)),
Case($("second"), o -> run(Main::second)),
Case($(), o -> run(() -> {
throw new RuntimeException("unknown");
}))
);

}

private static void second() { //some logic here }

private static void first() { //another logic here }
}

We can use some predicates in pattern matching like instanceOf(), isIn():

Object result = "some string";

Match(result).of(
Case($(instanceOf(Integer.class)), o -> run(() -> System.out.println("integer"))),
Case($(instanceOf(Double.class)), o -> run(() -> System.out.println("double"))),
Case($(isIn("some")), o -> run(() -> System.out.println("is in some"))),
Case($(isIn(1,2,3)), o -> run(() -> System.out.println("is in 1 2 3"))),
Case($(), o -> run(() -> {
throw new RuntimeException("unknown");
}))
);

  • Functional Try Catch

We can change try catch statements into functional style with Vavr.

Try is a monadic container in Vavr like Option or Lazy. So we can chain some sort of works using try:

Try.of(() -> {
throw new RuntimeException("runtime exception");
}).andThen(() -> System.out.println("success"))
.onFailure((t) -> System.out.println("failure: " + t.getMessage()))
.andFinally(() -> System.out.println("finally"));

We can merge pattern matching and Try together to take actions to exceptions:

A result = Try.of(this::bunchOfWork)
.recover(x -> Match(x).of(
Case($(instanceOf(Exception_1.class)), t -> somethingWithException(t)),
Case($(instanceOf(Exception_2.class)), t -> somethingWithException(t)),
Case($(instanceOf(Exception_n.class)), t -> somethingWithException(t))
))
.getOrElse(other);

Of course vavr does not limited with the aboves. It has many other features on functions and has some other data types.

For further information about vavr (like user defined patterns, data types, option type which we have optional in java 8 etc…) and examples take a look at my github account and vavr’s user guide.

Emre Savcı

Written by

Software Engineer @Trendyol & Software Development Enthusiast | Interested in Java&.Net DDD, CQRS, Event Sourcing, Scalability.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade