Implement pattern matching in Java with Vavr library
Tags: java, tutorial, programming
Published: 2020-04-23 18:21:50

---
title: Implement pattern matching in Java with Vavr library
published: true
description: 
tags: java, tutorial, programming
cover_image: https://images.pexels.com/photos/3231755/pexels-photo-3231755.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260
---

Hello, Dev.to! Today we explore _pattern matching_. This is what functional languages are famous for. Java and other C-like languages can "imitate" it to some degree (using multiple if or switch statements) but only to some degree. By default, Java can not conquer complex pattern matching conditions, but with Vavr it is much easier to implement.

In this post we will follow this approach: we will start with a brief dive to theory and then explore Vavr pattern matching API in-depth. By the way, this topic is close connected with other Vavr features, like [Option](https://www.mednikov.net/using-java-optional-vs-vavr-option/), [Streams](https://www.mednikov.net/streams-in-java-and-vavr/) and [Try](https://www.mednikov.net/handling-exceptions-with-try-catch-and-vavr-try/). 

## What is pattern matching?

Let dive a bit into theory and see what does computer science understand as _pattern matching_. From a technical point of view, this is a mechanism for checking a value against a pattern. We should differentiate it from pattern recognition: unlike latest, pattern matching assert __exact__ matches.

As it was mentioned earlier, C-like languages can emulate pattern matching feature up to some degree. For instance, we can use [switch statements](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html) to execute some logic based on match (for example, name):

```java
String name = "Carolina";

switch(name){
	case "Aneta":
		System.out.println("Hello, Aneta!");
		break;
	case "Barbora":
		System.out.println("Hello, Barbora!");
		break;
	case "Carolina":
		System.out.println("Hello, Carolina!");
		break;
	case "Denisa":
		System.out.println("Hello, Denisa!");
		break;
	default:
		System.out.println("Hello, stranger!");
		break;
}
```

Another behaviour, is to set a value, based on input. Let take a look on the another code snippet:

```java
enum DIAS{
	LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO
}

String weekday;
Dias dia = Dias.MIERCOLES;

switch(dia){
	case LUNES:
		weekday = "Monday";
		break;
	case MARTES:
		weekday = "Tuesday";
		break;
	case MIERCOLES:
		weekday = "Wednesday";
		break;
	case JUEVES:
		weekday = "Thursday";
		break;
	case VIERNES:
		weekday = "Friday";
		break;
	case SABADO:
		weekday = "Saturday";
		break;
	case DOMINGO:
		weekday = "Sunday";
		break;
}

System.out.println(weekday); // output: Wednesday
```
You can achieve same results with multiple if statements. However, both examples are very simple. But what if we need to write more complex conditions? Imagine, we have an app, that validates, if user first name of user is male or female. While it may seem discrimination for somebody, in Slavic languages we need to figure out gender of users in order to provide grammatically correct messages. This time let use if statements:

```java
String name = "Barbora";
String gender;

if (name.equalsIgnoreCase("Adam") || name.equalsIgnoreCase("Boris")){
	gender = "male";
} else if (name.equalsIgnoreCase("Anna") || name.equalsIgnoreCase("Barbora")){
	gender = "female";
}

System.out.println(gender); // output: female
```

Well, our app is pretty uneducated: it knows only 4 names! Imaginee, if we will add more names to this condition (just Czech ones, and there are other Slavic countires on the planet!)... Basically, what do we need to do is to have 2 lists of names: male ones and female ones and then assert, if input __is in__ the specific list. Well, we can do it like this:

```java
List<String> femaleNames = ...;
List<String> maleNames = ...;

String name = "Lukas";
String gender;

for (String n:femaleNames){
	if (name.equalsIgnoreCase(n)){
		gender = "female";
	}
}

for (String n:maleNames){
	if (name.equalsIgnoreCase(n)){
		gender = "male";
	}
}

System.out.println(gender); //output = "male"

```

As you can see, while we can immitate some pattern matching using "native" Java tools, they are very limited. Hopefully, you don't need to learn Haskell (although, it is a good idea) if you want to have pattern matching in your app. You can use Vavr library. Now, let see how to do it.

## An anatomy of Vavr pattern matching API

First, we will understand the structure of pattern matching API in Vavr library. It consists of three main elements: __Match__, __Case__ and patterns. Let explore them step by step.

### Match

Vavr provides a _Match API_ that is close to Scala’s match. It is represented by the class __io.vavr.API.Match<T>__. It is a starting point of pattern matching, that accepts a value, that we will need to _match_. Let take a look on the code snippet below:

```java
String dia = "Miercoles";
String weekday = Match(dia).of(
	Case($("Lunes"), "Monday"),
	Case($("Martes"), "Tuesday"),
	Case($("Miercoles"), "Wednesday"),
	Case($("Jueves"), "Thursday"),
	Case($("Viernes"), "Friday"),
	Case($("Sabado"), "Saturday"),
	Case($("Domingo"), "Sunday"));
```

Something like this! From a techincal point of view, __Match__ class is an easy structure:

1. Accepts _input value_ as argument
2. Produces new value as a result of condition matching as _value_ or _option_.

We already explored [Vavr Option](https://dev.to/andreevich/java-optional-vavr-option-an-essential-introduction-10cb) previously. In the example with days we produce exact value as a result of pattern matching. But we can return __Option__ too. Check this code:

```java
String number = "Four";

Option<Integer> digit = Match(number).of(
	Case($("One"), 1),
	Case($("Two"), 2),
	Case($("Three"), 3));

if (digit.isDefined()){
	System.out.println("Result  is: "+digit.get());
} else {
	System.out.println("No result!");
}
```

So, we don't have to always return exact value, as we can wrap the result of pattern matching as option. Let move to cases now.

### Case

Cases are defined in __API.Match.Case__. As you could note from previous example, this class  allows to match conditional patterns. Generally, it has following structure:

```java
Case($(predicate), ...)
```

With Case we can write much more concise code. There are two parts: 

* First, dollar-signed (that reminds me JQuery syntax) part - is condition to match
* Second part - produced value

As we will note later on, conditions can be simple and complex. Take a look on this example:

```java
int integer = 3;

String string = Match(integer).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

System.out.println(string);
```

This is a very easy assertion. We can different built in patterns to build conditions, as well combine multiple conditions at one predicate. Let modify our previous name with genders and names using __isIn__ predicate from Vavr:

```java
String name = "Carolina";

String gender = Match(name).of(
	Case($(isIn("Anna", "Beata", "Carolina", "Denisa")), "female"),
	Case($(isIn("Adam", "Boris", "Cyril", "David")), "male"));

System.out.println(gender);
```

Writing complex conditions is much easier with Vavr than with Java tools. Now, let move to patterns.

### Patterns

Let take a look on provided conditons in previous examples. You can note that they use several "models". There are three types of patterns in Vavr:

* __$(exact value)__ = the most common pattern. We check, that the value matches the _exact value_ provided.
* __$()__ = a _wildcard_. We use this pattern like __default__ in switches. In the previous example, we used __$()__ to handle cases, when input does not match any provided pattern.
* __$(predicate)__ = in this pattern we can apply a predicate function to the input and the resulting boolean value is used to make a decision.

We already saw usages of first two types: __$(exact value)__ and __$()__ wildcard. We also can use predicates - Vavr has various built-in predicates to make our developer's life easier. Let explore them.

## Built-in predicates

In the previous part, in the example with names and genders we used built-in __isIn__ predicate. There are many handy predicates that are already provided by Vavr to us. You can find them in __io.vavr.Predicates.*__. Let see them.

### is

One of the most common predicate is __is__ predicate. We already see examples of using Vavr to pattern matching. __is__ predicate tests, if an object is equal to the specified value using __Objects.equals(Object, Object)__ to compare. Let check an example:

```java
int integer = 2;

String string = Match(integer).of(
    Case($(is(1)), "one"),
    Case($(is(2)), "two"),
    Case($(), "nothing")
);
```

In the code snippet above we used __is__ to match __exact__ value of provided input argument. While with primitives and strings you can drop predicates and use just __$(exact value)__ pattern, with objects you need to use __is__, that will assert equality of objectts, based on __equals()__ method implementation.

### isIn

We talked before, that __isIn__ is a handy method to assert that value belongs to specific range of objects, likewise we did with names and genders. Here is an another usage of __isIn__ predicate - check even/odd number in Vavr's style:

```java
int number = 6;
String result = Match(number).of(
      Case($(isIn(2, 4, 6, 8)), "Even"), 
      Case($(isIn(1, 3, 5, 7, 9)), "Odd"));

System.out.println(result); //Even
```

You could understand __isIn__ predicate as __contains()__ method of Collections. When you use this predicate with custom objects, please note that, as with __is__, it also uses __equals__ logic to compare input and pattern.

### isNull/isNotNull

Input can be null, so we can use Vavr for [null checking](https://dzone.com/articles/using-java-optional-vs-vavr-option) too. There are two built-in predicates to do this:

* __isNull__ checks that provided input is null
* __isNotNull__ checks that provided input is not null

Let have a quick example:

```java
Object object = null;

String result = Match(object).of(
	Case($(isNull()), "Input is null"),
	Case($(isNotNull()), "Input is not null"));
```

### instanceOf

Java has __instanceOf__ operator. It is used to test whether the object is an instance of the specified type (class, subclass or interface). In a general form it looks like:

```
[Object] instanceof [Type]
```

Vavr also offers built-in __instanceOf__ predicate. It tests, if an object is instance of the specified type. Suppose we have a classes __Elephant__ and __Panda__ that both are child classes of __Animal__. Take a look on the code snippet below:

```java
Elephant john = new Elephant("John");
Panda xiao = new Panda("Xiao");

String who = Match(xiao).of(
	Case($(instanceOf(Elephant.class)), "This is an elephant, no doubts!"),
	Case($(instanceOf(Animal.class)), "It can be an elephant or not. But I am sure that is an animal!"));

System.out.pritnln(who);
```

You can find Javadoc for Predicate API [here](https://static.javadoc.io/io.vavr/vavr/0.9.2/io/vavr/Predicates.html). Up to now, we used a single predicate for pattern matching. However, we can combine multiple conditions. Let explore how to do it.

## Combine multiple predicates

There are three main ways to combine predicates in a one condition - these methods are also part of __Predicate__ package:

* __anyOf__ = combinator that checks if at least one of the given predicates is satisfied. 
* __allOf__ =  combinator that checks if all of the given predicates are satisfied. 
* __noneOf__ = combinator that checks if none of the given predicates is satisfied.

Let take an example to look how to combine multiple Vavr predicates:

```java
String word = "Tres";

String language = Match(word).of(
	Case($(anyOf(isIn("Lunes", "Martes","Miercoles"), isIn("Uno", "Dos", "Tres"))), "Spanish"),
	Case($(anyOf(isIn("Monday", "Tuesday", "Wednesday"), isIn("One", "Two", "Third"))), "English"));

System.out.println("Language is :"+language);
```

In the code snippet below we combine two conditions: word is either is in list of weekdays or in list of numbers. In case of match, Vavr tells us in which language exists the provided word. In same way we can build conditions to satisfy that all or none predicates are matched. Here is an another sample:

```java
Elephant elephant = new Elephant("John");
Elephant david = new Elephant("David");

Option<String> result = Match(elephant).of(
	Case($(allOf(instanceOf(Elephant.class), is(david))), "This elephant is David"));

if (result.isDefined()){
	System.out.println(result.get());
}
```

We match that __all__ conditions are satisfied. If you need to assert more specific conditions, consider to write your own predicates.

## Create custom predicates

In case built-in predicates do not offer required functionality, you can implement your own predicates using normal Java lambdas. Let take a look on a simple example:

```java
int number = 4;

String result = Match(number).of(
	Case($(n->n%2==0), "even"),
	Case($(n->n%2!=0), "odd"));

System.out.println(result);
```

In the code snippet above we use lambda predicates to assert the input to be even or odd. Another example can be FizzBuzz task. In case you don't know this classic programming problem: "Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz". ([reference](https://www.tomdalling.com/blog/software-design/fizzbuzz-in-too-much-detail/)).

In this example we can utilize several from aforesaid tools. Take a look on my implementation:

```java
int number = 45;

String message = Match(number).of(
		Case($(allOf((n->n%3==0), n(n->n%5==0))), "FizzBuzz"),
		Case($(n->n%5==0), "Buzz"),
		Case($(n->n%3==0), "Fizz"),
		Case($(), "Nothing"));

System.out.println(message);
```

This code uses __allOf__ predicate to assert both conditions to print __FizzBuzz__. Then there are two Java lambdas to validate single patterns and finally it has _wildcard_ __$()__ pattern. Gregor Trefs has another FizzBuzz implementation with [Vavr pattern matching](https://www.sitepoint.com/functional-fizzbuzz-with-vavr/#2patternmatching), that I invite you to check.

## Conclusion

During this post we explored how to write pattern matching in Java. While the language offers us several ways to immitate this functional programming concept, it is better to use Vavr library. We started from the structure of Match API and its elements. Next we observed built-in predicates offered out of the box, like __is__, __isIn__, __isNull__ etc. We also viewed how to use Java lambdas to build custom predicates and combine several conditions using __allOf__,__anyOf__ and __noneOf__. We will continue talk about Vavr and functional Java in future. Meanwhile, don't hesitate to drop questions in comments below or send me message via social channels.

## References

* Emre Savcı _Java Functional Programming & Pattern Matching With VAVR_ (2019) Medium, [read here](https://medium.com/@mstrYoda/java-functional-programming-pattern-matching-with-vavr-e280167962ee)
* Gregor Trefs _Six Ways to Functional FizzBuzz with Vavr_ (2017) SitePoint, [read here](https://www.sitepoint.com/functional-fizzbuzz-with-vavr/)
* Nikita Pavlenko _How to use Javaslang Pattern Matching?_ (2017), [read here](https://nikitapavlenko.wordpress.com/2017/02/22/how-to-use-javaslang-pattern-matching/)