public final classOptional{}
Optional是一個為了解決NullPointerException設(shè)計而生可以包含對象也可以包含空的容器對象异袄。封裝了很多對空處理的方法也增加了filter娇澎、map這樣的檢索利器媒抠,其中函數(shù)式編程會有種炫酷到爆的感覺渴析。
基礎(chǔ)測試用例對象:
public classJava8OptionalTest{
? ? List<String> stringList = null;
? ? ICar car = new WeiLaiCar();
}public classWeiLaiCarimplementsICar{
? ? Integer wheels = new Integer(4);
}
Api中提供的4種optional
最核心的當屬Optional對象辆憔,泛型的引入支持了所有對象類型焙畔,又增加對常用場景下的double\int\long進行擴展捎琐。重點介紹一下Optional對象的方法其他三個類似蓄髓。
public final class Optional<T> {
public final class OptionalDouble {
public final class OptionalInt {
public final class OptionalLong {
@FunctionalInterface
Predicate\Consumer\Supplier三個接口都是函數(shù)式接口
靜態(tài)方法of
privateOptional(){this.value =null;}
構(gòu)造方法被private叉庐,不能new但提供了of這樣的靜態(tài)方法去初始化類;
public static <T> Optionalof(T value){
? ? return new Optional<>(value);
}public static <T> OptionalofNullable(T value){
? ? return value == null ? empty() : of(value);
}publicstatic Optionalempty(){
? ? @SuppressWarnings("unchecked")
? ? Optional<T> t = (Optional<T>) EMPTY;
? ? return t;
}
1会喝、empty支持你去創(chuàng)建一個空的optional類陡叠,這樣的類直接get()會報錯:java.util.NoSuchElementException: No value present
2、of(x)傳入的對象不能為null肢执,而ofNullable(x)是支持傳入null的對象枉阵,一般用這兩個比較多。
present 方法
isPresent是用來判斷optional中對象是否為null预茄,ifPresent的參數(shù)是當對象不為null時執(zhí)行的lamdba表達式兴溜。
publicbooleanisPresent(){
? ? return value != null;
}publicvoidifPresent(Consumer consumer){
? ? if (value != null)
? ? ? ? consumer.accept(value);
}
示例詳解介紹了ifPresent特性:
Java8OptionalTest test = new Java8OptionalTest();
Optional<Java8OptionalTest> optional = Optional.of(test);
pringTest(optional.isPresent());//trueoptional.ifPresent( a -> pringTest(a.getCar().getClass().getName()));//com.ts.util.optional.WeiLaiCaroptional.ifPresent( a -> Optional.ofNullable(a.getStringList()).ifPresent(b -> pringTest("StringList:" + (b == null))));//第一級的ifPresent是存在test對象,所以執(zhí)行了lambda表達式耻陕,而第二級的ifPresent的stringList是null拙徽,所以沒有執(zhí)行表達式optional.ifPresent( a -> Optional.ofNullable(a.getCar()).ifPresent(b -> pringTest("car:" + (b == null))));//car:false//第二級ifPresent的car對象是存在的,所以第二級的表達式執(zhí)行了
map 方法
源碼提供了兩種map和flatMap诗宣。
map方法的參數(shù)是個當包含的對象不為null時才執(zhí)行的lambda表達式膘怕,返回該表達式執(zhí)行結(jié)果的封裝optional對象,同理支持鏈式調(diào)用召庞,逐層深入和遞歸遞進很像岛心;
flatMap區(qū)別在于lambda表達式的返回結(jié)果必須主動包裹Optinoal,否則報錯
public Optionalmap(Function mapper){
? ? Objects.requireNonNull(mapper);
? ? if (!isPresent())
? ? ? ? return empty();
? ? else {
? ? ? ? return Optional.ofNullable(mapper.apply(value));
? ? }
}public OptionalflatMap(Function> mapper){
? ? Objects.requireNonNull(mapper);
? ? if (!isPresent())
? ? ? ? return empty();
? ? else {
? ? ? ? return Objects.requireNonNull(mapper.apply(value));
? ? }
}
測試示例:
Java8OptionalTest test = new Java8OptionalTest();
Optional<Java8OptionalTest> optional = Optional.of(test);
Optional opt1 = optional.map( a -> a.getCar());
pringTest(opt1.get());//com.ts.util.optional.WeiLaiCar@5d6f64b1int wheel = 0;//傳統(tǒng)null判斷寫法if(test != null){
? ? if(test.getCar() != null){//實際業(yè)務里面層級也許會超過3層? ? ? ? wheel = test.getCar().getWheelCount();
? ? }
}
pringTest("傳統(tǒng):"+wheel);//傳統(tǒng):4Optional opt2 = optional.map( a -> a.getCar()).map(b -> b.getWheelCount());//Optional支持下的寫法pringTest("optinal:"+opt2.get());//optinal:4Optional opt3 = optional.map( a -> a.getStringList()).map(b -> b.size());
pringTest(opt3);//Optional.emptyOptional opt4 = optional.flatMap(a -> Optional.of(a.getCar()));//主動包裹Optional對象pringTest(opt4);//Optional[com.ts.util.optional.WeiLaiCar@5d6f64b1]Optional opt5 = optional.flatMap(a -> Optional.of(a.getCar())).flatMap(b -> Optional.ofNullable(b.getWheelCount()));
pringTest(opt5);//Optional[4]
filter 方法
源碼如下:
publicOptionalfilter(Predicate predicate){
? ? Objects.requireNonNull(predicate);
? ? if (!isPresent())
? ? ? ? return this;
? ? else? ? ? ? return predicate.test(value) ? this : empty();
}
filter方法傳入一個斷言語句條件的lambda表達式裁眯,返回一個原對象的optional包裝鹉梨,所以支持鏈式調(diào)用;只要記住這三點你便掌握如何使用了穿稳。
看下面的例子:
Java8OptionalTest test = new Java8OptionalTest();
Optional<Java8OptionalTest> optional = Optional.of(test);
Optional result = optional.filter( a -> a.getCar() != null).filter( b -> b.getClass().getName() != null);
pringTest(result.isPresent()? result.get().getClass().getName(): result.isPresent());//com.ts.util.Java8OptionalTestOptional result1 = optional.filter( a -> a.getStringList() != null);
pringTest(result1.get());//java.util.NoSuchElementException: No value present
orElse 方法
Api提供了三個方法存皂。
orElse 當optional內(nèi)對象為null就返回這個參數(shù),比較像很多默認值設(shè)置逢艘;
orElseGet 基本同orElse旦袋,區(qū)別是傳入?yún)?shù)支持lambda表達式,返回的就是表達式執(zhí)行結(jié)果它改;
orElseThrow 也是傳入lambda表達式疤孕,但是表達式是拋出異常
publicTorElse(T other){
? ? return value != null ? value : other;
}publicTorElseGet(Supplier<? extends T> other){
? ? return value != null ? value : other.get();
}public <X extends Throwable> TorElseThrow(Supplier<? extends X> exceptionSupplier)throwsX{
? ? if (value != null) {
? ? ? ? return value;
? ? } else {
? ? ? ? throw exceptionSupplier.get();
? ? }
}
測試用例如下:
Java8OptionalTest one = null;
Java8OptionalTest test = new Java8OptionalTest();
Optional<Java8OptionalTest> optional = Optional.ofNullable(one);
pringTest(optional);//Optional.emptypringTest(optional.orElse(test));//com.ts.util.Java8OptionalTest@5197848cpringTest(optional.orElseGet(() -> new Java8OptionalTest()));//com.ts.util.Java8OptionalTest@5d6f64b1pringTest(optional.orElseThrow(() -> new RuntimeException("orElseThrow")));//java.lang.RuntimeException: orElseThrow
覺得不錯請點贊支持,歡迎留言或進我的個人群855801563領(lǐng)取【架構(gòu)資料專題目合集90期】央拖、【BATJTMD大廠JAVA面試真題1000+】祭阀,本群專用于學習交流技術(shù)鹉戚、分享面試機會,拒絕廣告专控,我也會在群內(nèi)不定期答題抹凳、探討