Search code examples
javalambdafunctional-interface

Java - lambda infer type


I'm playing around with uses of a FunctionalInterface. I've seen multiple variations of the following code everywhere:

int i = str != null ? Integer.parseInt() : null;

I'm looking for the following behaviour:

int i = Optional.of(str).ifPresent(Integer::parseInt);

But ifPresent only accepts a Supplier and Optional cannot be extended.

I have created the following FunctionalInterface:

@FunctionalInterface
interface Do<A, B> {

    default B ifNotNull(A a) {
        return Optional.of(a).isPresent() ? perform(a) : null;
    }

    B perform(A a);
}

This allows me to do this:

Integer i = ((Do<String, Integer>) Integer::parseInt).ifNotNull(str);

One can add more default methods to do things like

LocalDateTime date = (Do<String, LocalDateTime> MyDateUtils::toDate).ifValidDate(dateStr);

And it reads nicely Do [my function] and return [function return value] if [my condition] holds true for [my input], otherwise null.

Why can't the compiler infer the types of A (String passed to ifNotNull) and B (Integer returned by parseInt) when I do the following:

Integer i = ((Do) Integer::parseInt).ifNotNull(str);

This results in:

incompatible types: invalid method reference


Solution

  • For your original problem Optional is powerful enough to deal with nullable values

    Integer i = Optional.ofNullable(str).map(Integer::parseInt).orElse(null);
    

    For date example it would look like

    Date date = Optional.ofNullable(str).filter(MyDateUtils::isValidDate).map(MyDateUtils::toDate).orElse(null);
    

    Regarding type error

    Integer i = ((Do<String, Integer>) Integer::parseInt).ifNotNull(str);
    

    Specifying generic arguments for Do interface solves a problem. The thing is that just Do without specified type arguments means Do<Object, Object> and Integer::parseInt does not match this interface.