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:
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.