Home > Enterprise >  Optional - Unhandled exception using orElseThrow()
Optional - Unhandled exception using orElseThrow()

Time:12-05

I want to throw a custom exception in case parsing fails, but the compiler complains that there is an unhandled ParserException that comes from the parse() method.

But What am I missing?

My code:

public void validateConstraints(RequestType body) {
    
    SimpleDateFormat simpleDateFormatYearMonth = new SimpleDateFormat("yyyy-MM-dd");
    
    Date date = Optional
        .ofNullable(body.date())
        .map(simpleDateFormatYearMonth::parse)
        .orElseThrow(() -> new InvalidCustomException(""));
}

CodePudding user response:

TL;DR

  • Your apparent issue stems from the fact java.util.Function as well as many other functional interfaces doesn't declare to throw any checked Exceptions in its abstract method. For that reason, implementations can't violate the contract providing behavior which is less safe than declared.

Here's a quote from the Java Language Specification §8.4.8.3. Requirements in Overriding and Hiding:

For every checked exception type listed in the throws clause of m2, that same exception class or one of its supertypes must occur in the erasure (§4.6) of the throws clause of m1; otherwise, a compile-time error occurs.

With that being said, you can't propagate a checked exception outside the lambda or method reference (since it's not declared, it should be handled right on the spot).

  • Creating an Optional only for the purpose of hiding null-check, and chaining methods on it is a misuse of Optional since it goes against its design goal.

  • java.util.Date (and java.sql.Date) as well as SimpleDateFormat are obsolete since Java 8 (reminder: this version was released more than 10 years ago). As a replacement we have a new Time API, represented by classes that reside in java.time package, like Instant, LocalDateTime, DateTimeFormatter, etc.

Avoid using Optional to replace Null-checks

The design goal of the Optional is to serve as a return type, and its method ofNullable() is supposed to wrap a nullable return value, not to perform validation.

You might be interested in reading:

Here's a short quote from the linked above answer by @StuartMarks, Java and OpenJDK developer:

A typical code smell is, instead of the code using method chaining to handle an Optional returned from some method, it creates an Optional from something that's nullable, in order to chain methods and avoid conditionals.

To validate if a value is not null JDK offers overloaded method Objects.requireNoneNull(), which was specifically designed for that purpose. But in this case it's not applicable because you need to throw your custom exception (requireNoneNull() operates via NPE, you can only provide a custom message).

The last thing worth to point out before diving into the solution, is that there's nothing wrong with implicit null-checks (if you have quite a bit of them that's an issue, which is rooted in a way your classes and behavior are designed, rather than related to the tools offered by the language).

Therefore, I would advise to implement this functionality using a plain conditional logic:

public static final SimpleDateFormat YEAR_MONTH_DAY = new SimpleDateFormat("yyyy-MM-dd");

public void validateConstraints(RequestType body) {
    if (tryParse(body.date()) == null) throw new InvalidCustomException("message");
}

private Date tryParse(String str) {
    Date date = null;
    try {
        if (str != null) date = YEAR_MONTH_DAY.parse(str);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return date;
}
  • Related