7

Assume that I have this code in my project:

public List<T> getAll(Integer parameter) {
    if(parameter != null && parameter > -1) {
        // do something here
    }
}

My question is: how can I do the checking with Optional instead of using if, or if there is another thing I could use?

Grzegorz Piwowarek
  • 13,172
  • 8
  • 62
  • 93
Rasool Ghafari
  • 4,128
  • 7
  • 44
  • 71
  • 3
    If the parameter is optional, then create two methods: One without parameters and one expecting an int. Neither `if` nor `Optional` are good choices here. – a better oliver Nov 14 '16 at 12:27
  • Cannot agree with that comment. Consider three parameters which are all optional. Surely you are not suggesting to make 2^3=8 overloads of the method, especially if every parameter is an Integer (making several different signatures indistinguishable). Of course sometimes we can gather all params inside some other entity, but we will again need to deal with them being optional. – Maksim Gumerov Apr 30 '18 at 18:46

5 Answers5

19

Optional's design was inspired by monads known from the world of Functional Programming. In such case, it could look like this:

public List<T> getAll(Integer parameter) {

    return Optional.ofNullable(parameter)
      .filter(p -> p > -1)
      .map(p -> *some modification*) //this line is optional
      .orElseGet(() -> *some default value, probably an empty list*)
}

In such case, condition checking is performed in the filter method. If a given Predicate is not matched, the underlying Optional will be empty.

If you want to perform an operation on the underlying value, use map method by providing it with a Function that should be applied to the element wrapped by the Optional.

At the end, you can simply perform some action using ifPresent(), thrown an exception orElseThrow or simply return a default value with orElse or orElseGet. Keep in mind that orElseGet accepts a Supplier instance which makes it evaluate the default value lazily.

If you want to dig deeper, check out @stuart-marks talk from Devoxx: https://www.youtube.com/watch?v=Ej0sss6cq14&t=2767s

In your case, there might be no need for an Optional at all. Just two methods. One with the parameter and the other without.

Grzegorz Piwowarek
  • 13,172
  • 8
  • 62
  • 93
  • 4
    I'm sorry for being accepted answer. Upvoting your answer and wishing you a populist badge here. – xenteros Nov 14 '16 at 12:28
  • _"it should look like this"_ I don't think so. In a comment to another answer you wrote _"Optional as a param is a code smell", but your code essentially does just that. Whether you expect an `Optional` or create one makes no difference. The code smell is the optional parameter, not the usage of `Optional`. – a better oliver Nov 14 '16 at 13:23
  • 3
    @zeroflagL well, creating an Optional instance only to benefit from the API is questionable but keep in mind that it's encapsulated and not exposed to the world. You do not force users to wrap everything into an Optional. – Grzegorz Piwowarek Nov 14 '16 at 13:29
9

You should not use Optional for such a case

As Stuart Marks states in Optional - The Mother of All Bikesheds:

Rule #4: It's generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value.

This creates a useless overhead without any improvement for code readability and maintainability. You should thus not wrap your parameter into an optional.

and

Rule #6: Avoid using Optional in fields, method parameters and collections.

Avoid using Optional in method parameters

  • it doesn't really work for making parameters optional
  • forces call sites to create Optionals for everything:

    myMethod(Optional.of("some value"));

    myMethod(Optional.empty());

See also Why should Java 8's Optional not be used in arguments.

Community
  • 1
  • 1
Didier L
  • 18,905
  • 10
  • 61
  • 103
3

Use Optional<Integer>

public List<T> getAll(Integer paramter) {
    return Optional.ofNullable(parameter)
      .filter(p -> p > -1);
}

The Optional<> is just an implementation of Optional pattern. The useful methods is also Optional<T>#orElse(T default) which sets the value to default in case there was a null,

If you already got interested but still can't answer your doubts, please ask for clarification in comments. I'll respond asap.

xenteros
  • 15,586
  • 12
  • 56
  • 91
  • Or [`OptionalInt`](https://docs.oracle.com/javase/8/docs/api/java/util/OptionalInt.html) – khelwood Nov 14 '16 at 11:28
  • I decided to use Optional, as the OP uses reference type. – xenteros Nov 14 '16 at 11:31
  • 1
    The if-condition could be shortened to parameter.filter((i) -> i > -1).isPresent() – Nevay Nov 14 '16 at 11:31
  • 1
    @Nevay not every beginner is familiar with lambdas, so I decided to show the *traditional* way. – xenteros Nov 14 '16 at 11:33
  • 1
    @xenteros The OP couldn't help but use a reference type, because they were allowing it to be null - hence converting to an optional type. – khelwood Nov 14 '16 at 11:33
  • @khelwood ofc you're right. I'm thinking about extending the answer. – xenteros Nov 14 '16 at 11:34
  • 8
    You should not use `Optional` as a parameter to a method. I found this good answer that explains why: http://stackoverflow.com/a/39005452/4137489 – marstran Nov 14 '16 at 11:40
  • 5
    This answer is really bad. Optional as a param is a code smell and proposed way of using an Optional has nothing to do with how it should be used. – Grzegorz Piwowarek Nov 14 '16 at 11:41
  • 1
    Don’t use `if (parameter.isPresent()`… Use `parameter.ifPresent(`… (works with `OptionalInt` as well as `Optional`). – Ole V.V. Nov 14 '16 at 12:09
  • Thanks, @marstran, for the very informative link. So I gather: (a) if the caller typically has an `Integer` that may be null, the original method signature should be preserved, and the implementer may look into pivovarit’s answer. (b) if the caller typically would do either `getAll(4)` or `getAll(null)`, the method should be overloaded with one version taking an `int` argument and one version taking no argument. – Ole V.V. Nov 14 '16 at 12:24
-1

You need to be clear about what you expect of your method. Possibilities:

  • You want it to keep working as before, and handle the case where the client supplies a null
  • You want to change the method to accept Optional<Integer> as its parameter. The "no nulls" way, is to do this, and simply not accommodate callers who supply null -- if they get a NullPointerException, it's their own fault because they broke the rules.

You don't have to work with streams or lambdas to work with Optional (although of course, you can).

You could simply write:

public List<T> getAll(Optional<Integer> maybeParameter) {
    if(maybeParameter.isPresent() && maybeParameter.get() > -1) {
        // do something here
    }
}

Look at Optional's other methods in JavaDoc, to see how else it can be used.

If you didn't want to change the signature of your method, you could use Optional.ofNullable() to turn an Integer into an Optional<Integer>:

public List<T> getAll(Integer parameter) {
    Optional<Integer> maybeParameter = Optional.ofNullable(parameter);
    // work with the Optional here as before...
}

However I question the value of doing this here. If your API accepts nulls, then handling it with Optional "behind the scenes" doesn't provide an advantage.

I feel the best use of Optional is to expose it as part of your API. If a parameter is optional, declare it as Optional rather than handling null (or better, use method overloading, so they don't have to pass anything at all). If a return value might not be set, make the return type Optional, rather than ever returning null.

slim
  • 40,215
  • 13
  • 94
  • 127
-2
import java.util.Optional;

public class ExampleNullCheck{

    public static void main(String args[])
    {
        Integer a = null;
        Optional<Integer> checkInt = Optional.ofNullable(a);
        System.out.println(checkInt.isPresent());
    }//main

}//class
Hulk
  • 6,399
  • 1
  • 30
  • 52