Optional.orElse与Optional.orElseGet的区别

Java8加入了Optional这一利器用来对付null。它里边就包含了orElseorElseGet方法。
单看方法及注释的话,它俩的区别就是接收的参数不一样,以及一个返回null,另一个则不允许。
不过最近在使用过程中发现它俩还有一个区别,就是无论Optional中的值为不为null
orElse都会有执行,而orElseGet则不会执行。

下面通过一个简单的代码段来测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static String other() {
System.out.println("call other method");
return "nothing";
}

public static String orElseMethod(String s) {
return Optional.ofNullable(s).orElse(other());
}

public static String orElseGetMethod(String s) {
return Optional.ofNullable(s).orElseGet(() -> other());
}

public static void main(String[] args) throws Exception {
String s = null;
System.out.println("----------orElse---------");
System.out.println(orElseMethod(s));
System.out.println("----------orElseGet---------");
System.out.println(orElseGetMethod(s));
}

output:
----------orElse---------
call other method
nothing
----------orElseGet---------
call other method
nothing

查看输出信息可以得知,当Optional值为null的时候,orElseorElseGet都执行了对应的方法并且返回了候补值。
当传入的值不为null时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception {
String s = "a";
System.out.println("----------orElse---------");
System.out.println(orElseMethod(s));
System.out.println("----------orElseGet---------");
System.out.println(orElseGetMethod(s));
}

output:
----------orElse---------
call other method
a
----------orElseGet---------
a

这时orElseGet里的方法并不会执行,而orElse里的方法还是会执行。

乍看之下,它俩有点像单例模式中的饿汉模式懒汉模式,一个是事先准备好返回值,
另一个则是需要用到的时候才去构造对应的返回值。因此这样看某些情况下orElseGetorElse性能会好一些?

跑个分看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
public class OptionalTest {

@Param({"sss"})
public String s = null;

public String other() {
return "nothing";
}

@Benchmark
public String orElseMethod() {
return Optional.ofNullable(s).orElse(other());
}

@Benchmark
public String orElseGetMethod() {
return Optional.ofNullable(s).orElseGet(() -> other());
}

public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder().include(OptionalTest.class.getSimpleName())
.forks(2)
.warmupIterations(4).warmupTime(TimeValue.seconds(1))
.measurementIterations(10).measurementTime(TimeValue.seconds(1))
.threads(4)
.build();
new Runner(options).run();
}
}

output:
Benchmark (s) Mode Cnt Score Error Units
OptionalTest.orElseGetMethod sss thrpt 40 494.108 ± 16.033 ops/us
OptionalTest.orElseMethod sss thrpt 40 461.837 ± 36.228 ops/us

这里的评测指标为吞吐量Throughput,表示指定时间内能执行多少次调用。那自然分数是越高越好。
从这个测试结果来看,orElseGet是比orElse分数高的,当然测试用例的不同分数自然不一样,此次跑分结果仅供娱乐。