前言:
北京時間2018年9月26日韵丑,Oracle官方發(fā)布Java 11屎飘。既然版本都更新到11了,現(xiàn)在才來學(xué)8是不是太晚了垦写?其實不是的,目前應(yīng)該大部分都還是使用的Java 7和Java 8版述,這兩個應(yīng)該還是主流梯澜。而Java 8 又有一些激動人心的新特性,所以還是值得學(xué)習(xí)的渴析。Java 8 新特性主要有以下幾點:
- Lambda表達(dá)式(重點)晚伙;
- 函數(shù)式接口;
- 方法引用與構(gòu)造器引用俭茧;
- Stream API(重點)咆疗;
- 接口中的默認(rèn)方法與靜態(tài)方法;
- 新時間日期API母债;
- 其他新特性午磁。
有了以上新特性尝抖,Java 8就可以做到:
- 速度更快;
- 代碼更少(增加了新的語法 Lambda 表達(dá)式)迅皇;
- 方便操作集合(Stream API)
- 便于并行昧辽;
- 最大化減少空指針異常 Optional。
接下來一起來了解一下Java 8的這些新特性登颓。
歡迎大家關(guān)注我的公眾號 javawebkf搅荞,目前正在慢慢地將簡書文章搬到公眾號,以后簡書和公眾號文章將同步更新框咙,且簡書上的付費文章在公眾號上將免費咕痛。
一、Lambada表達(dá)式:
1喇嘱、什么是lambda茉贡?
Lambda 是一個匿名函數(shù),我們可以把 Lambda 表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞)者铜∏簧ィ可以寫出更簡潔、更靈活的代碼王暗。
2悔据、了解新操作符:
Java 8引入了新的操作符,->俗壹,叫箭頭操作符或者叫l(wèi)ambda操作符科汗。當(dāng)使用lambda表達(dá)式時就需要使用這個操作符。
3绷雏、lambda表達(dá)式語法:
箭頭操作符將lambda表達(dá)式分成了兩部分:
- 左側(cè):lambda表達(dá)式的參數(shù)列表(接口中抽象方法的參數(shù)列表)
- 右側(cè):lambda表達(dá)式中所需執(zhí)行的功能(lambda體头滔,對抽象方法的實現(xiàn))
語法有如下幾種格式:
- 語法格式一(無參數(shù)無返回值): () -> 具體實現(xiàn)
- 語法格式二(有一個參數(shù)無返回值): (x) -> 具體實現(xiàn) 或 x -> 具體實現(xiàn)
- 語法格式三(有多個參數(shù),有返回值涎显,并且lambda體中有多條語句):(x,y) -> {具體實現(xiàn)}
- 語法格式四:若方法體只有一條語句坤检,那么大括號和return都可以省略
注:lambda表達(dá)式的參數(shù)列表的參數(shù)類型可以省略不寫,可以進(jìn)行類型推斷期吓。
看幾個例子:
例一:
@Test
public void test1(){
// 實現(xiàn)一個線程
int num = 0;//jdk1.8以前早歇,這個必須定義為final,下面才能用讨勤,1.8后默認(rèn)就為final
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("hello world"+ num);
}
};
runnable.run();
}
創(chuàng)建一個線程箭跳,重寫run方法,在run方法里面打印一句話潭千。我們想要的就是System.out.println("hello world"+ num);
這行代碼谱姓,但是為了實現(xiàn)這行代碼,不得不多寫了好多行刨晴。lambda就可以解決這一點屉来,看看用lambda如何實現(xiàn):
Runnable runnable1 = () -> System.out.println("hello world"+num);
runnable1.run();
用lambda這樣就搞定了路翻。首先還是Runnable runnable1 =
,但是不用new了茄靠,右邊就用lambda實現(xiàn)茂契。我們要使用的是該接口的run方法,run方法不需要參數(shù)慨绳,所以lambda表達(dá)式左邊就是()账嚎,lambda表達(dá)式右邊是抽象方法的實現(xiàn),也就是第一種方式中run方法的方法體寫到lambda表達(dá)式右邊就可以了儡蔓。
例二:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);//就這一行關(guān)鍵代碼
}
};
以前寫一個比較器就要像上面那樣寫,先new比較器類疼邀,然后在其compare方法里寫核心代碼喂江。用lambda實現(xiàn):
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
compare方法需要兩個參數(shù),所以箭頭操作符左邊寫(x,y)旁振,右邊是compare方法的實現(xiàn)获询,所以應(yīng)該寫return Integer.compare(o1,o2);
,但是根據(jù)上面的語法格式四可知拐袜,return可以省略吉嚣,因此就寫成了上面那樣。
通過這兩個例子可以感受到lambda表達(dá)式的簡潔蹬铺,但是問題來了:我們說lambda表達(dá)式就是一個匿名函數(shù)尝哆,我們只需要指定參數(shù)和lambda體即可,那么它是如何判斷重寫的是哪個方法呢甜攀?比如一個接口中有多個方法秋泄,如果使用lambda表達(dá)式來寫,那么如何判斷我們使用的是該接口的哪個方法规阀?其實是不能判斷的恒序!通過上面兩個例子可以發(fā)現(xiàn),Runnable接口和Comparator接口都是只有一個方法的接口谁撼,所以可以使用lambda歧胁。
二、函數(shù)式接口:
1厉碟、什么是函數(shù)式接口喊巍?
像Runnable和Comparator這樣只有一個方法的接口,稱為函數(shù)式接口墨榄。也可以在接口上加上@FunctionalInterface
注解玄糟,如果編譯通過,則該接口就是函數(shù)式接口袄秩。lambda表達(dá)式就需要函數(shù)式接口的支持阵翎。
2逢并、看一個需求:
需求:需要對兩個數(shù)進(jìn)行加減乘除等運算,怎么實現(xiàn)郭卫?
- 傳統(tǒng)做法:傳統(tǒng)做法中砍聊,需要進(jìn)行幾種運算,我們就要寫幾個方法贰军。一種運算對應(yīng)一個方法玻蝌。
- lambda做法:首先要定義一個函數(shù)式接口,接口中只有一個方法词疼,接收兩個參數(shù)俯树。
@FunctionalInterface
public interface MyInterface {
public Integer getValue(Integer num1,Integer num2);
}
然后就可以使用了:
@Test
public void test5(){
MyInterface myInterface = (x,y) -> x*y;//乘法運算
MyInterface myInterface1 = (x,y) -> x+y;//加法運算
Integer result1 = myInterface.getValue(100,200);
Integer result2 = myInterface1.getValue(1024,2048);
System.out.println(result1);
System.out.println(result2);
}
所以用lambda的話,只需要定義一個函數(shù)式接口贰盗,不管進(jìn)行什么操作许饿,都可以用lambda解決,不用再一種運算對應(yīng)一個方法舵盈。但是陋率,還需要自己定義函數(shù)式接口,好像也沒簡單很多秽晚。Java考慮到這點了瓦糟,所以內(nèi)置了函數(shù)式接口。
3赴蝇、四大內(nèi)置函數(shù)式接口:
為了不需要我們自己定義函數(shù)式接口菩浙,Java內(nèi)置了四大函數(shù)式接口,這四大接口加上它們的子類扯再,完全滿足我們的使用了芍耘。四大函數(shù)式接口是:
- Consumer<T>:消費型接口(void accept(T t)),接收一個參數(shù)熄阻,無返回值斋竞。
- Supplier<T>:供給型接口(T get()),無參數(shù)秃殉,有返回值坝初。
- Function<T,R>:函數(shù)型接口(R apply(T t)),接收一個參數(shù)钾军,有返回值鳄袍。
- Predicate<T>:斷言型接口(boolean test(T t)),接收一個參數(shù)吏恭,返回Boolean值拗小。
4、四大函數(shù)式接口的使用:
接下來看看具體如何使用這四大函數(shù)式接口樱哼。
消費型接口的使用:
Consumer consumer = (x) -> System.out.println("消費了"+x+"元");
consumer.accept(100);
供給型接口的使用:
Supplier<Integer> supplier = () -> (int)(Math.random() * 100);//生成隨機(jī)數(shù)
System.out.println(supplier.get());
函數(shù)型接口的使用:
Function<String,String> function = str -> str.toUpperCase();//將傳入的字符串轉(zhuǎn)成大寫
String s = function.apply("adcdefggffs");
System.out.println(s);
斷言型接口的使用:
//需求:將滿足條件的字符串添加到集合中去
public List<String> filterString(List<String> strings, Predicate<String> predicate){
List<String> stringList = new ArrayList<>();
for (String string : strings) {
if (predicate.test(string)){
stringList.add(string);
}
}
return stringList;
}
//測試
@Test
public void test4(){
List<String> list = Arrays.asList("hello","world","niu","bi");
List<String> newList = filterString(list,str -> str.length() > 3);//選出長度大于3的字符串
newList.forEach(System.out::println);
}
三哀九、方法引用與構(gòu)造器引用:
當(dāng)要傳遞給Lambda體的操作剿配,已經(jīng)有實現(xiàn)的方法了,可以使用方法引用阅束。不過實現(xiàn)抽象方法的參數(shù)列表呼胚,必須與引用方法的參數(shù)列表保持一致。
1息裸、方法引用語法:
- 對象::實例方法
- 類::靜態(tài)方法
- 類::實例方法
2蝇更、方法引用具體用法:
說了那么多可能還不清楚到底什么意思,一起來看幾個例子呼盆。
語法一例子:
Consumer<String> consumer = x -> System.out.println(x);//傳統(tǒng)寫法
Consumer<String> consumer = System.out::println;//使用方法引用
println方法和Consumer的accept方法都是無返回值年扩,接收一個參數(shù),所以可以這樣寫访圃。
語法二例子:
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
//因為compare方法已經(jīng)被Integer實現(xiàn)了常遂,且是靜態(tài)的,所以這樣用就行挽荠。
Comparator<Integer> comparator1 = Integer::compare;
語法三例子:
BiPredicate<String,String> biPredicate = (x,y) -> x.equals(y);
//可以改成如下寫法
//不過要滿足:第一個參數(shù)是實例方法的調(diào)用者,第二個參數(shù)是實例方法的參數(shù)時平绩,就可以這樣用
BiPredicate<String,String> biPredicate1 = String::equals;
3圈匆、構(gòu)造器引用:
Supplier<Employee> supplier = () -> new Employee();
//可以改寫成這樣
//注意:需要調(diào)用的構(gòu)造器的參數(shù)列表要與函數(shù)接口中抽象方法的參數(shù)列表一致
Supplier<Employee> supplier1 = Employee::new;
Employee employee = supplier.get();
四、Stream API:
Stream 是 Java8 中處理集合的關(guān)鍵抽象概念捏雌,它可以指定你希望對集合進(jìn)行的操作跃赚,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作性湿。使用Stream API 對集合數(shù)據(jù)進(jìn)行操作纬傲,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作肤频。簡而言之叹括,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
1宵荒、理解Stream:
Stream被稱作流汁雷,是用來處理集合以及數(shù)組的數(shù)據(jù)的。它有如下特點:
- Stream 自己不會存儲元素报咳。
- Stream 不會改變源對象侠讯。相反,他們會返回一個持有結(jié)果的新Stream暑刃。
- Stream 操作是延遲執(zhí)行的厢漩。這意味著他們會等到需要結(jié)果的時候才執(zhí)行。
2岩臣、使用Stream的三個步驟:
- 創(chuàng)建Stream:一個數(shù)據(jù)源(如:集合溜嗜、數(shù)組)宵膨,獲取一個流
- 中間操作:一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理
- 終止操作:一個終止操作粱胜,執(zhí)行中間操作鏈柄驻,并產(chǎn)生結(jié)果
3、創(chuàng)建Stream:
直接看代碼:
//1焙压、通過集合提供的stream方法或parallelStream()方法創(chuàng)建
List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream();
//2鸿脓、通過Arrays中的靜態(tài)方法stream獲取數(shù)組流
Employee[] employees = new Employee[10];
Stream<Employee> stream = Arrays.stream(employees);
//3、通過Stream類的靜態(tài)方法of()創(chuàng)建流
Stream<String> stream1 = Stream.of("aa","bb","cc");
//4涯曲、創(chuàng)建無限流
//迭代方式創(chuàng)建無限流
//從0開始野哭,每次加2,生成無限個
Stream<Integer> stream2 = Stream.iterate(0,(x) -> x+2);
//生成10個
stream2.limit(10).forEach(System.out::println);
//生成方式創(chuàng)建無限流
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
上面介紹了集合幻件、數(shù)組創(chuàng)建流的幾種方式拨黔,都有對應(yīng)的注解。
4绰沥、中間操作:
篩選與切片:
- filter -- 接收lambda篱蝇,從流中排除某些數(shù)據(jù)。
- limit -- 截斷流徽曲,使其元素不超過給定數(shù)量零截。
- skip(n) -- 跳過元素,返回一個扔掉了前n個元素的流秃臣,若不足n個元素涧衙,則返回空流。
- distinct -- 篩選奥此,通過流所生成元素的hashCode()和equals()去除重復(fù)元素,所以對象必須重新hashCode方法和equals方法弧哎。
看代碼:
employees.stream()//已有employees集合
.filter((e) -> e.getAge() > 18)//中間操作(選出年齡大于18的)
.limit(1)//中間操作(只返回一個)
.forEach(System.out::println);//終止操作
映射:
- map -- 接收lambda,將元素轉(zhuǎn)換成其他形式或提取信息稚虎。接收一個函數(shù)作為參數(shù)撤嫩,該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素蠢终。
- flatMap -- 接收一個函數(shù)作為參數(shù)非洲,將流中的每個值都換成另一個流,然后把所以流連接成一個流蜕径。
看例子:
List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream()
.map(str -> str.toUpperCase())//將所有的轉(zhuǎn)成大寫
.forEach(System.out::println);
排序:
- sorted() -- 自然排序(按照Comparable來排序)两踏。
- sorted(Comparator com) -- 定制排序(按照Comparator來排序)。
看例子:
List<String> list = Arrays.asList("ccc","bbb","aaa","ddd");
list.stream()
.sorted()//自然排序
.forEach(System.out::print);//aaa,bbb,ccc,ddd
//定制排序
employees.stream()//employees是一個存有多名員工的集合
.sorted((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())){ //如果年齡一樣
return e1.getName().compareTo(e2.getName());//就比較姓名
}else {
return e1.getAge().compareTo(e2.getAge());//年齡不一樣就比較年齡
}
}).forEach(System.out::println);
5兜喻、終止操作:
查找與匹配:
- allMatch -- 檢查是否匹配所有元素梦染。
- anyMatch -- 檢查是否至少匹配一個元素。
- noneMatch -- 檢查是否沒有匹配所有元素。
- findFirst -- 返回第一個元素帕识。
- findAny -- 返回當(dāng)前流中任意元素泛粹。
- count -- 返回流中元素總個數(shù)。
- max -- 返回流中最大值肮疗。
- min -- 返回流中最小值晶姊。
//看看employee集合中是不是所有都是男的
boolean b = employees.stream()
.allMatch(e -> e.getGender().equals("男"));
System.out.println(b);
規(guī)約:
- reduce(T identity,BinaryOperator) -- 可以將流中元素反復(fù)結(jié)合起來,得到一個值伪货。
//規(guī)約求和
List<Integer> list = Arrays.asList(1,3,5,4,4,3);
Integer sum = list.stream()
.reduce(0,(x,y) -> x+y);//首先把0作為x们衙,把1作為y,進(jìn)行加法運算得到1碱呼,把1再作為x蒙挑,把3作為y,以此類推
System.out.println(sum);
//獲取工資總和
Optional<Double> optional = employees.stream()
.map(Employee::getSalary)//提取工資
.reduce(Double::sum);//求工資總和
System.out.println(optional2.get());
收集:
- collect -- 將流轉(zhuǎn)換為其他形式愚臀。接收一個Collector接口的實現(xiàn)忆蚀,用于給Stream中元素做匯總的方法。
//把公司中所有員工的姓名提取出來并收集到一個集合中去
List<String> stringList = employees.stream()
.map(Employee::getName)//提取員工姓名
//.collect(Collectors.toList());//收集到list集合
//.collect(Collectors.toSet());//收集到set集合
.collect(Collectors.toCollection(LinkedList::new));//這種方式可收集到任意集合
stringList.forEach(System.out::println);//遍歷集合
//計算工資平均值
Double avgSalary = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avgSalary);
//根據(jù)年齡分組
Map<Integer,List<Employee>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getAge));
System.out.println(map);
//先按性別分組姑裂,性別一樣時按年齡分組
Map<String,Map<Integer,List<Employee>>> map1 = employees.stream()
.collect(Collectors.groupingBy(Employee::getGender,Collectors.groupingBy(Employee::getAge)));
System.out.println(map1);
//分區(qū)馋袜,滿足條件的一個區(qū),不滿足的另一個區(qū)
Map<Boolean,List<Employee>> map2 = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 6000));//工資大于6000的為true區(qū)舶斧,否則為false區(qū)
System.out.println(map2);
//獲取工資的總額桃焕、平均值等
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getSum());
System.out.println(dss.getAverage());
System.out.println(dss.getMax());
五、并行流與串行流:
1捧毛、fork/join框架:
此框架就是在必要的情況下,將一個大任務(wù)让网,進(jìn)行拆分(fork)成若干個小任務(wù)(拆到不可再拆時)呀忧,再將一個個的小任務(wù)運算的結(jié)果進(jìn)行 join 匯總。
2溃睹、并行流與串行流:
通過上面的圖可以知道而账,使用fork/join框架可以提高效率(運算量越大越明顯,運算量可能反而更慢因篇,因為拆分也需要時間)泞辐,但是在Java 8之前需要自己實現(xiàn)fork/join,還是挺麻煩的竞滓,Java 8就方便多了咐吼,因為提供了并行流,底層就是使用了fork/join商佑。Stream API 可以聲明性地通過 parallel() 與 sequential() 在并行流與順序流之間進(jìn)行切換锯茄。
@Test
public void test(){
Instant start = Instant.now();
//普通做法求0加到10000000000的和
LongStream.rangeClosed(0,100000000000L)
.reduce(0,Long::sum);
Instant end = Instant.now();
System.out.println("耗費"+ Duration.between(end ,start) + "秒");//55秒
}
@Test
public void test2(){
Instant start = Instant.now();
//并行流求0加到10000000000的和
LongStream.rangeClosed(0,100000000000L)
.parallel()//使用并行流
.reduce(0,Long::sum);
Instant end = Instant.now();
System.out.println("耗費"+ Duration.between(end ,start) + "秒");//30秒
}
通過運行上面的程序可以明顯感受到并行流的高效。
六、新時間日期API:
Java 8之前的Date和Calendar都是線程不安全的肌幽,而且使用起來比較麻煩晚碾,Java 8提供了全新的時間日期API,LocalDate(日期)喂急、LocalTime(時間)格嘁、LocalDateTime(時間和日期) 、Instant (時間戳)廊移、Duration(用于計算兩個“時間”間隔)糕簿、Period(用于計算兩個“日期”間隔)等。
1画机、LocalDate冶伞、LocalTime、LocalDateTime:
這三個用法一樣步氏。
//獲取當(dāng)前系統(tǒng)時間
LocalDateTime localDateTime = LocalDateTime.now();//當(dāng)前時間日期
LocalDateTime localDateTime2 = localDateTime.plusYears(2);//加兩年
System.out.println(localDateTime.getMonth());
System.out.println(localDateTime);
System.out.println(localDateTime2);
//指定時間
LocalDateTime localDateTime1 = LocalDateTime.of(2018,12,13,21,8);
System.out.println(localDateTime1);
2腰耙、Instant 時間戳:
時間戳就是計算機(jī)讀的時間,它是以Unix元年(傳統(tǒng) 的設(shè)定為UTC時區(qū)1970年1月1日午夜時分)開始算起的腾啥。
//計算機(jī)讀的時間:時間戳(Instant)霜旧,1970年1月1日0時0分0秒到此時的毫秒值
Instant instant = Instant.now();
System.out.println(instant);//默認(rèn)是美國時區(qū),8個時差
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));//加上時差
System.out.println(offsetDateTime);
System.out.println(instant.toEpochMilli());//顯示毫秒值
3界阁、Duration 和 Period:
LocalTime localTime = LocalTime.now();
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
LocalTime localTime1 = LocalTime.now();
System.out.println(Duration.between(localTime,localTime1).toMillis());
//獲取兩個日期之間的間隔
LocalDate localDate = LocalDate.of(2012,1,1);
LocalDate localDate1 = LocalDate.now();
Period period = Period.between(localDate,localDate1);
System.out.println(period);
System.out.println(period.getYears()+"年"+period.getMonths()+"月"+period.getDays()+"日");
4侯繁、時間校正器(TemporalAdjuster):
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(1);//localDate日期中月份的1號
System.out.println(localDateTime1);
localDateTime1.with(TemporalAdjusters.firstDayOfNextMonth());//下一個月的第一天
localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//下周日
5、格式化日期(.DateTimeFormatter ):
@Test
public void test6(){
//DateTimeFormatter:格式化
//使用預(yù)設(shè)格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime localDateTime = LocalDateTime.now();
String str = localDateTime.format(dateTimeFormatter);
System.out.println(str);
System.out.println("==========================");
//自定義格式
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String str2 = localDateTime.format(dateTimeFormatter1);
//這樣格式化也可以
String str3 = dateTimeFormatter1.format(localDateTime);
System.out.println(str2);
System.out.println(str3);
//退回到解析前的格式
LocalDateTime newDate = localDateTime.parse(str,dateTimeFormatter);
System.out.println(newDate);
}
6泡躯、時區(qū)的處理:
Java8 中加入了對時區(qū)的支持贮竟,帶時區(qū)的時間為分別為:ZonedDate、ZonedTime较剃、ZonedDateTime咕别。
@Test
public void test7(){
//ZonedDate ZonedTime ZonedDateTime
LocalDateTime dateTime = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
System.out.println(dateTime);
}
七、接口中的默認(rèn)方法和靜態(tài)方法:
public interface MyInterface {
default String test(){
return "允許存在有具體實現(xiàn)的方法";
}
public static String test2(){
return "接口中還可以有靜態(tài)方法";
}
}
如上所示写穴,Java 8的接口中允許有默認(rèn)方法和靜態(tài)方法惰拱。如果一個類繼承了一個類還實現(xiàn)了一個接口,而且接口中的默認(rèn)方法和父類中的方法同名啊送,這時采用類優(yōu)先原則偿短。也就是說,子類使用的是父類的方法馋没,而不是接口中的同名方法昔逗。
八、其他新特性:
1篷朵、Optional類:
這個類是為了盡可能減少空指針異常的纤子。就是把普通對象用Optional包起來,做了一些封裝】嘏穑看看其用法:
@Data
public class Man { //男人類
private Godness godness;//女神
}
@Data
public class Godness {
private String name;
public Godness(String name){
this.name = name;
}
public Godness(){
}
}
//獲取男人心中的女神的名字(有的人不一定有女神泽论,也就是說女神可能為空)
//常規(guī)做法要加很多判斷
public String getGodnessName(Man man){
if (man != null){
Godness godness = man.getGodness();
if (godness != null){
return godness.getName();
}else{
return "我心中沒有女神";
}
}else {
return "男人為空";
}
}
一個man類,有一個成員變量女神卡乾,女神也是一個類翼悴,有一個成員變量,名字幔妨。要獲取man心中的女神鹦赎,為了防止控制針異常,要做很多的判斷误堡。如果使用Optional呢古话?做法如下:
//新男人類
@Data
public class NewMan {
private Optional<Godness> godness = Optional.empty();
}
//使用optional后的方法
public String getGodnessName2(Optional<NewMan> man){
return man.orElse(new NewMan())
.getGodness()
.orElse(new Godness("我沒有女神"))
.getName();
}
這樣就簡單多了。
2锁施、重復(fù)注解與類型注解:
Java 8 可以使用重復(fù)注解和類型注解陪踩,如下圖:
總結(jié):
本文說了一些Java 8 的新特性,重點就是lambda表達(dá)式和Stream API悉抵,可以簡化很多操作肩狂。肯可能還有些文中未涉及的姥饰,在此拋磚引玉傻谁,望各位大佬指點!