2

I am trying to explore the the use of Vavr library within my Java application. I am trying to reduce the if-else ladder using the Vavr library's Match.of() construct.

Here is a piece of code that I have written:

Match(Option.of(clientId)).of(
                Case($None(), run(() -> {
                    metricsService.recordValidationStageMetrics(CLIENT_ID_NOT_PRESENT, type, BLANK);
                    log.error("Client ID not present in the request header: [{}]", clientId);
                    throw new ValidationException(EX_REQUEST_CLIENT_ID_EMPTY);
                })),
                Case($Some($(StringUtils::isBlank)), run(() -> {
                    metricsService.recordValidationStageMetrics(CLIENT_ID_NOT_PRESENT, type, BLANK);
                    log.error("Client ID not present in the request header: [{}]", clientId);
                    throw new ValidationException(EX_REQUEST_CLIENT_ID_EMPTY);
                })),
                Case($(), run(() -> {
                    if (isClientIdNotAllowed(clientId)) {
                        log.error(LOG_CLIENT_ID_NOT_ALLOWED, clientId);
                        metricsService.recordValidationStageMetrics(CLIENT_ID_NOT_ALLOWED, type, clientId);
                        throw new ValidationException(EX_ALLOWED_CLIENT_ID_ERROR);
                    }
                }))
        );

The problem here is that the Option is always matching the first Case statement. Even if the clientId is non-null, it is validated to None and throws the exception.

So the question is:

  1. Why is it not behaving in an intended way? What is it that I am missing here?
  2. Is there a cleaner way to write this?
Opal
  • 81,889
  • 28
  • 189
  • 210

1 Answers1

4

Actually - as far as I remember - you need to prepend the run with () -> which indicates the Supplier variant of the second argument for Case being used. Otherwise it will be evaluated eagerly and hence the first Case will be run.

The following code works fine:

package lol;

import static io.vavr.API.$;
import static io.vavr.API.Case;
import static io.vavr.API.Match;
import static io.vavr.API.run;
import static io.vavr.Patterns.$None;
import static io.vavr.Patterns.$Some;

import io.vavr.control.Option;

public class Lol {

  public static void main(String[] args) {
    String val = "lol";
    Match(Option.of(val)).of(
        Case($None(), () -> run(() -> {
          System.out.println(1);
          throw new IllegalArgumentException("null");
        })),
        Case($Some($(String::isEmpty)), () -> run(() -> {
          System.out.println(2);
          throw new IllegalArgumentException("empty");
        })),
        Case($(), () -> run(() -> {
          System.out.println(3);
          if ("lol".equals(val)) {
            throw new IllegalArgumentException("lol");
          }
        }))
    )
    ;
  }
}

Try with removing the () -> and you'll start getting the first Case being matched no matter what the input is.

Whether I can be written cleaner. It depends on the version of java you use. I see it as a switch statement or pattern matching if the latest is used.

Opal
  • 81,889
  • 28
  • 189
  • 210
  • I was trying to write better and more readable code. Is VAVR a better alternative to java switch statements? I have read a lot of arguments on this, but could not find anything definitive (maybe because it isn't). But from one dev to another, what is your take on it? – Gurucharan Sharma Jun 22 '22 at 15:47
  • @GurucharanSharma no it's not. Actually it was for some time but with the advent of the latest changes in java I would not be using it. Also it seems to be very verbose, however it's quite hard to implement pattern matching non-natively. Today I'd just use java constructs, they look very promising. – Opal Jun 27 '22 at 06:45
  • Thank you so much, Opal. Also in your answer above you mentioned - "I see it as a switch statement or pattern matching if the latest is used." Would you please provide some references for the pattern matching in the latest java versions? Is it similar to regex pattern matching? – Gurucharan Sharma Jun 27 '22 at 17:13