2

Is there any Java 8 API static method that runs a Function on non-null input, but returns nullValue on a null input?

I can easily write this method myself, but I'd rather use a standard one if it exists.

public static <T, R> R transform(final T t, final Function<T, R> rFromT, final R nullValue) {
    return
        t == null
            ? nullValue
            : rFromT.apply(t)
    ;
}

// which can be called like:
final Number x = getNumberThatCouldBeNull();
final long   y = transform(x, Number::longValue, 0L);
XDR
  • 4,070
  • 3
  • 30
  • 54
  • 3
    The historical trend in Java has been to tell you that you shouldn't be dealing with null in the first place and that you should throw NullPointerExceptions as soon as possible. – Louis Wasserman Feb 12 '16 at 21:53
  • The JDK has no such method. Also, what could `nullValue` possibly be apart from `null`? – fge Feb 12 '16 at 22:06
  • @fge `nullValue` is the value that is returned if `t == null`, instead of calling `rFromT`. See the last line of my code block, where I pass `0L` as the value for `nullValue`. – XDR Feb 12 '16 at 22:44
  • I don't think such a `transform` method would make things any clearer. `x == null ? 0L : x.longValue()` is short, clear, and perfectly fine Java 8 code. – glts Feb 13 '16 at 00:22
  • @glts A) it prevents typo bugs, e.g., `x == null ? 0L : z.longValue()`, B) it obviates the need for the x variables, e.g. `transform(getNumberThatCouldBeNull(), Number::longValue, 0L);` – XDR Feb 13 '16 at 00:57

3 Answers3

7

You can just use the new Optional API in Java 8:

final Number x = getNumberThatCouldBeNull();
final long   y = Optional.ofNullable(x).map(Number::longValue).orElse(0L);

If x is not null, it will be mapped to its long value and it will be returned; else 0 will be returned.

Of course, if you want to hide that inside a method, you could have the following:

public static <T, R> R transform(final T t, final Function<T, R> mapper, final R nullValue) {
    return Optional.ofNullable(t).map(mapper).orElse(nullValue);
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 3
    Or better let getNumberThatCouldBeNull return the Optional if its in your control – Alexander Oh Feb 12 '16 at 21:53
  • 1
    I don't see the necessity of instantiating multiple `Optional`s, calling many methods that perform redundant checks, etc., just to avoid adding & using a single static method that does exactly what I want. – XDR Feb 12 '16 at 22:02
  • 2
    @XDR Like Alex has mentioned, the method `getNumberThatCouldBeNull` should probably return an `Optional` to begin with. It is actually why Optional were primarily introduced: as a return-type ([read here](http://stackoverflow.com/q/23454952/1743880)). Then you really don't need that static utility, you just append calls to `map` and return a default with `orElse` or `orElseGet`. – Tunaki Feb 12 '16 at 22:06
  • 1
    @XDR the JDK is not-so-subtly pressuring you to stop using nulls at all. – Louis Wasserman Feb 12 '16 at 22:16
  • `getNumberThatCouldBeNull` is a third-party method, in my current use case. – XDR Feb 12 '16 at 22:40
0

It seems that no such method exists in the Java 8 API.

If anyone does find one that has been overlooked, please let everyone know.

Please see the answer from @Tunaki, and everyone else's comments, for usage of Optional.

In my use case, however, the method that supplies the Object that can be null is third-party, so using Optional doesn't offer any benefits in my case, and is less performant.

XDR
  • 4,070
  • 3
  • 30
  • 54
0

You could also take a different approach. Instead of encapsulating the null-check and function invocation in a method, you could create a higher-order function that would take your function and the provided default value as arguments, and would return a new function:

public static <T, R> Function<T, R> transform(
        Function<T, R> mapper,
        R defaultValue) {

    return t -> Optional.ofNullable(t)
            .map(mapper)
            .orElse(defaultValue);
}

This new function, when applied, would perform the null-check and would either return the provided default value or the value returned by the original function.

Example:

Function<Number, Long> transformed = transform(Number::longValue, 0L);

Number x = getNumberThatCouldBeNull();

long longNumber = transformed.apply(x);

The advantage of this approach is that the null-check is performed lazily.

fps
  • 33,623
  • 8
  • 55
  • 110