Preface
After we’ve made our first big steps into functional programming in the last post, we will talk about Optionals in today’s part.
Why do we need Optionals?
Hand on heart, you also think that null is annoying, don’t you? For every argument which can be null, you have to check whether it is null or not:
- if(argument == null) {
- throw new NullPointerException();
- }
Introducing Optionals
In Java 8, java.util.Optional
- Integer i = 5;
- Optional
optinalI = Optional.of(i);
How do optionals work?
Optional have two states. They either hold an object or they hold null. If they hold an object, Optional are called present, if they hold null, they are called empty. If they are not empty, you can get the object in the Optional by using Optional.get(). But be careful, because a get() on an empty optional will cause a NoSuchElementException. You can check if a optional is present by calling the method Optional.isPresent(). Below is a simple example:
- public void playingWithOptionals() {
- String s = "Hello World!";
- String nullString = null;
- Optional
optionalS1 = Optional.of(s); // Will work - Optional
optionalS2 = Optional.ofNullable(s); // Will work too - Optional
optionalNull1 = Optional.of(nullString); // -> NullPointerException - Optional
optionalNull2 = Optional.ofNullable(nullString); // Will work - System.out.println(optionalS1.get()); // prints "Hello World!"
- System.out.println(optionalNull2.get()); // -> NoSuchElementException
- if(!optionalNull2.isPresent()) {
- System.out.println("Is empty"); // Will be printed
- }
- }
1. Working with Optional and null
- public void workWithFirstStringInDB() {
- DBConnection dB = new DBConnection();
- Optional
first = dB.getFirstString(); - if(first != null) {
- String value = first.get();
- //...
- }
- }
2. Using isPresent() and get()
2.1. Doing something when the value is present
- public void workWithFirstStringInDB() {
- DBConnection dB = new DBConnection();
- Optional
first = dB.getFirstString(); - if(first.isPresent()) {
- String value = first.get();
- //...
- }
- }
- public void workWithFirstStringInDB() {
- DBConnection dB = new DBConnection();
- Optional
first = dB.getFirstString(); - first.ifPresent(value -> /*...*/);
- }
2.2. Returning a Modified Version of the Value
- public Integer doubleValueOrZero(Optional
value) { - if(value.isPresent()) {
- return value.get() * 2;
- }
- return 0;
- }
- public Integer doubleValueOrZero(Optional
value) { - return value.map(i -> i * 2).orElse(0);
- }
There is another really cool method that you can use with Optionals. It’s called flatMap(). When you use map on a method that returns an Optional, you basically get an Optional
This is the reason there is flatMap. It flattens the Optional
- public void showFlatMap() {
- Optional
two = Optional.of(2.0); - Optional
zero = Optional.of(0.0); - two.flatMap(num -> divide(1.0, num)).orElse(0.0); // 0.5
- zero.flatMap(num -> divide(1.0, num)).orElse(0.0); // 0.0
- }
- public Optional
divide(Double first, Double second) { - if(second == 0.0) {
- return Optional.empty();
- }
- return Optional.of(first / second);
- }
You can find a lot of books, talks and discussions about the question: Should you use null or Optional in some particular case. And both have their right to be used. In the linked talk, you will find a nice rule which you can apply in most of the cases. Use Optionals when “there is a clear need to represent ‘no result’ or where null is likely to cause errors.”. So you shouldn’t use Optionals like this:
- public String defaultIfOptional(String string) {
- return Optional.ofNullable(string).orElse("default");
- }
- public String defaultIfOptional(String string) {
- return (string != null) ? string : "default";
- }
Conclusion
That’s it for today! We have played with the Optional class. It’s a container class for other classes which is either present or not present(empty). We have removed some common code smell that comes with Optionals and used functions as objects again. We also discussed when you should use null and when Optionals. In the next part, we will use Streams as a new way to handle a Collection of Objects.
Supplement
* An Introduction to Functional Programming in Java ... Part 1 - Functions as Objects
* An Introduction to Functional Programming in Java 8: Part 3 - Streams
沒有留言:
張貼留言