痛點(diǎn)
在java編碼過程中兵拢,大家碰到的最多的異常是什么介褥,我相信必然這貨NullPointerException
必然是排行第一的。那我們在平時編碼中曲聂,有各種編碼規(guī)范與其相關(guān)霹购,比如時時的判斷null
,方法禁止返回null
等朋腋,例如
public void bindUserToRole(User user) {
if (user != null) {
String roleId = user.getRoleId();
if (roleId != null) {
Role role = roleDao.findOne(roleId);
if (role != null) {
role.setUserId(user.getUserId());
roleDao.save(role);
}
}
}
}
或者
public String bindUserToRole(User user) {
if (user == null) {
return;
}
String roleId = user.getRoleId();
if (roleId == null) {
return;
}
Role = roleDao.findOne(roleId);
if (role != null) {
role.setUserId(user.getUserId());
roleDao.save(role);
}
}
為了防止NullPointerException
齐疙,好好的代碼寫成這個鳥樣,或許下面的會看上去比較順眼一點(diǎn)旭咽,但是大體還是一樣的贞奋。
其實(shí)我們有一種更為優(yōu)雅的方式來完成上面的功能,如下
Optional<String> roleOpt = Optional.ofNullable(user).map(User::getRoleId);
if(roleOpt.isPresent()){
....
}
這樣穷绵,我們僅需要對我們關(guān)心的做一次校驗轿塔,省卻了前面的一系列的檢驗操作。
Optional的引入
基于上述的一些原因请垛,在JDK8中催训,引入了一個新的類java.util.Optional
,來避免這類問題的處理宗收。
先看下類的說明
A container object which may or may not contain a non-null value.If a value is present,
isPresent()
will returntrue
andget()
will return the value.
這里面說明這是一個可以包含null
或者非null
的容器漫拭,其最基本的兩個操作就是isPresent()
和get()
,基本用起來就是這樣
if( oneOptional.isPresent() ){
String s = oneOptional.get();
....
}
首先我們看下這個類中包含哪些方法混稽,如下
首先采驻,其有一個成員變量和一個定義的常量如下
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
其中value
表示其封裝的真實(shí)的對象,EMPTY
是定義的一個表示空的常量匈勋。構(gòu)造方法很很簡單礼旅,兩個常見的私有構(gòu)造方法Optional()
和Optional(T)
,其中不帶參的默認(rèn)設(shè)置value
為null
洽洁,帶參的構(gòu)造函數(shù)痘系,不允許傳null
。
Optional
類包含3個靜態(tài)方法生成Optional
對象饿自,分別為
-
Optional<T> empty()
生成一個空Optional
對象汰翠,其value
為null
-
Optional<T> of(T value)
調(diào)用Optional(T)
構(gòu)造方法龄坪,其value
不允許為null
-
Optional<T> ofNullable(T value)
與Optional<T> of(T value)
的差別是其傳入的value
允許為null
下面簡單介紹一下里面的各個方法和一些簡單的使用示例
-
get()
返回value
,若為null
則拋出異常NoSuchElementException
-
isPresent()
判斷當(dāng)前的value
是否為null
-
ifPresent(Consumer<? super T> consumer)
該方法支持傳入一個Consumer
對象复唤,當(dāng)value
不為null
的時候調(diào)用健田,為null
則不做任何操作,示例如下
public void testIfPresent(){
Optional<String> optional=Optional.of("zh");
optional.ifPresent(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
配合lambda
使用佛纫,代碼更為簡潔
public void testIfPresent(){
Optional<String> optional=Optional.of("zh");
optional.ifPresent(s -> System.out.println(s));
}
-
filter(Predicate<? super T> predicate)
顧名思義妓局,這個方法的作用就是filter(過濾),該方法用于過濾一個Optional
對象呈宇,通過傳入的Predicate
對象中的一個test
方法好爬,例如
Optional<String> optional=Optional.of("aa");
Optional<String> optionalResult=optional.filter(s -> s.startsWith("a"));
System.out.println(optionalResult);
輸出結(jié)果是
Optional[aa]
由于其返回仍是一個Optional
對象,我們可以有如下較為優(yōu)雅的寫法
Optional<String> optionalResult=optional.filter(s -> s.startsWith("a"))
.filter(s -> s.length()==2)
.filter(s -> s.endsWith("a"));
-
map(Function<? super T, ? extends U> mapper)
此方法支持一個Function
參數(shù)攒盈,在這個Function
里面可以對這個Optional
對象做一些操作或者改變抵拘,其返回值仍為一個Optional
類型,例如
Optional<String> optional=Optional.of("aa");
Optional<Integer> result= optional.map(s -> s.toUpperCase())
.map(s->s.length());
輸出結(jié)果為
Optional[2]
map
提供一種優(yōu)雅的流式的方式來替代先前繁雜的if
判斷和數(shù)據(jù)處理
-
flatMap(Function<? super T, Optional<U>> mapper)
和map
類似型豁,只不過需要我們手動將方法的返回僵蛛,封裝成Optional
對象,如
Optional<Integer> result= optional.flatMap(s -> Optional.of(s.toUpperCase()))
.flatMap(s -> Optional.of(s.length()));
其余功能與map
一致 迎变。
-
orElse(T other)
這個方法較為簡單充尉,參數(shù)為一個默認(rèn)值,即若value
為null
衣形,則返回默認(rèn)值
Optional<String> optional=Optional.of("aa");
System.out.println(optional.orElse("bb"));
Optional<String> optional1=Optional.ofNullable(null);
System.out.println(optional1.orElse("bb"));
輸出為
aa
bb
-
orElseGet(Supplier<? extends T> other)
提供一個Supplier
入?yún)⑼障溃?code>Supplier提供一個默認(rèn)值,例如
Optional<String> optional=Optional.ofNullable(null);
System.out.println(optional.orElseGet(() -> "aaa"));
-
orElseThrow(Supplier<? extends X> exceptionSupplier)
顧名思義谆吴,若為null
則拋出異常
Optional<String> optional=Optional.ofNullable(null);
System.out.println(optional.orElseThrow(() -> new RuntimeException()));
使用場合注意
Reports calls to java.util.Optional.get() without first checking with a isPresent() call if a value is available. If the Optional does not contain a value, get() will throw an exception.
Optional.get() 前不事先用 isPresent() 檢查值是否可用. 假如 Optional 不包含一個值, get() 將會拋出一個異常
Reports any uses of java.util.Optional<T>, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not
使用任何像 Optional 的類型作為字段或方法參數(shù)都是不可取的. Optional 只設(shè)計為類庫方法的, 可明確表示可能無值情況下的返回類型. Optional 類型不可被序列化, 用作字段類型會出問題的