Jdk8相對之前的jdk加入了很多的新特性叫潦。
1:jdk中加入了default關(guān)鍵字官硝。
在java里面短蜕,我們通常都是認(rèn)為接口里面是只能有抽象方法,不能有任何方法的實現(xiàn)的朋魔,那么在jdk1.8里面打破了這個規(guī)定,引入了新的關(guān)鍵字default警检,通過使用default修飾方法,可以讓我們在接口里面定義具體的方法實現(xiàn)扇雕。代碼如下:
所以說這個default方法是所有的實現(xiàn)類都不需要去實現(xiàn)的就可以直接調(diào)用窥摄,那么比如說jdk的集合List里面增加了一個sort方法镶奉,那么如果定義為一個抽象方法崭放,其所有的實現(xiàn)類如arrayList,LinkedList等都需要對其添加實現(xiàn),那么現(xiàn)在用default定義一個默認(rèn)的方法之后币砂,其實現(xiàn)類可以直接使用這個方法了,這樣不管是開發(fā)還是維護(hù)項目道伟,都會大大簡化代碼量使碾。
2:Lambda表達(dá)式
Lambda表達(dá)式是jdk1.8里面的一個重要的更新蜜徽,這意味著java也開始承認(rèn)了函數(shù)式編程票摇,并且嘗試引入其中。首先矢门,什么是函數(shù)式編程,引用廖雪峰先生的教程里面的解釋就是說:函數(shù)式編程就是一種抽象程度很高的編程范式祟剔,純粹的函數(shù)式編程語言編寫的函數(shù)沒有變量,因此物延,任意一個函數(shù),只要輸入是確定的叛薯,輸出就是確定的笙纤,這種純函數(shù)我們稱之為沒有副作用组力。而允許使用變量的程序設(shè)計語言省容,由于函數(shù)內(nèi)部的變量狀態(tài)不確定燎字,同樣的輸入,可能得到不同的輸出候衍,因此,這種函數(shù)是有副作用的脱柱。函數(shù)式編程的一個特點就是,允許把函數(shù)本身作為參數(shù)傳入另一個函數(shù)榨为,還允許返回一個函數(shù)!簡單的來說就是随闺,函數(shù)也是一等公民了,在java里面一等公民有變量矩乐,對象,那么函數(shù)式編程語言里面函數(shù)也可以跟變量散罕,對象一樣使用了,也就是說函數(shù)既可以作為參數(shù)欧漱,也可以作為返回值了,看一下下面這個例子误甚。
//這是常規(guī)的Collections的排序的寫法,需要對接口方法重寫
????????public void test1(){
????????List<String> list =Arrays.asList("aaa","fsa","ser","eere");
????????Collections.sort(list, new Comparator<String>() {
????????????@Override
????????????public int compare(String o1, String o2) {
????????????????return o2.compareTo(o1);
????????????}
????????});
????????for (String string : list) {
????????????System.out.println(string);
????????}
????}
//這是帶參數(shù)類型的Lambda的寫法
????????public void testLamda1(){
????????List<String> list =Arrays.asList("aaa","fsa","ser","eere");
????????Collections.sort(list, (Comparator<? super String>) (String a,String b)->{
????????????return b.compareTo(a);
????????}
????????);
????????for (String string : list) {
????????????System.out.println(string);
????????}
????}
//這是不帶參數(shù)的lambda的寫法
????????public void testLamda2(){
????????List<String> list =Arrays.asList("aaa","fsa","ser","eere");
????????Collections.sort(list, (a,b)->b.compareTo(a)
????????);
????????for (String string : list) {
????????????System.out.println(string);
????????}
可以看到不帶參數(shù)的寫法一句話就搞定了排序的問題擅威,所以引入lambda表達(dá)式的一個最直觀的作用就是大大的簡化了代碼的開發(fā)冈钦,像其他一些編程語言Scala郊丛,Python等都是支持函數(shù)式的寫法的。當(dāng)然宾袜,不是所有的接口都可以通過這種方法來調(diào)用,只有函數(shù)式接口才行庆猫,jdk1.8里面定義了好多個函數(shù)式接口,我們也可以自己定義一個來調(diào)用月培,下面說一下什么是函數(shù)式接口
3:函數(shù)式接口
定義:“函數(shù)式接口”是指僅僅只包含一個抽象方法的接口,每一個該類型的lambda表達(dá)式都會被匹配到這個抽象方法杉畜。jdk1.8提供了一個@FunctionalInterface注解來定義函數(shù)式接口,如果我們定義的接口不符合函數(shù)式的規(guī)范便會報錯此叠。
看一下這個接口的調(diào)用,符合lambda表達(dá)式的調(diào)用方法灭袁。
MyLamda m = y -> System.out.println("ss"+y);
4:方法與構(gòu)造函數(shù)引用
1.8提供了另外一種調(diào)用方式::,當(dāng) 你 需 要使用 方 法 引用時 倦炒, 目 標(biāo)引用 放 在 分隔符::前 ,方法 的 名 稱放在 后 面 逢唤,即ClassName :: methodName。例如 鳖藕,Apple::getWeight就是引用了Apple類中定義的方法getWeight。請記住吊奢,不需要括號纹烹,因為你沒有實際調(diào)用這個方法召边。方法引用就是Lambda表達(dá)式(Apple a) -> a.getWeight()的快捷寫法,如下示例片挂。
因此對構(gòu)造方法的調(diào)用:
@FunctionalInterface
public interface MyLamda {
????public void test1(String y);
//這里如果繼續(xù)加一個抽象方法便會報錯
// ???public void test1();
//default方法可以任意定義
????default String test2(){
????????return "123";
????}
????default String test3(){????????
????????return "123";
????}
這里的User::new就是調(diào)用了User的構(gòu)造方法,Java編譯器會自動根據(jù)UserFactory.get方法的簽名來選擇合適的構(gòu)造函數(shù)音念。
5沪饺、局部變量限制
Lambda表達(dá)式也允許使用自由變量(不是參數(shù)闷愤,而是在外層作用域中定義的變量),就像匿名類一樣讥脐。 它們被稱作捕獲Lambda。 Lambda可以沒有限制地捕獲(也就是在其主體中引用)實例變量和靜態(tài)變量旬渠。但局部變量必須顯式聲明為final,或事實上是final告丢。 為什么局部變量有這些限制岖免? (1)實例變量和局部變量背后的實現(xiàn)有一個關(guān)鍵不同觅捆。實例變量都存儲在堆中,而局部變量則保存在棧上栅炒。如果Lambda可以直接訪問局部變量,而且Lambda是在一個線程中使用的赢赊,則使用Lambda的線程,可能會在分配該變量的線程將這個變量收回之后释移,去訪問該變量。因此玩讳, Java在訪問自由局部變量時,實際上是在訪問它的副本熏纯,而不是訪問原始變量。如果局部變量僅僅賦值一次那就沒有什么區(qū)別了——因此就有了這個限制误窖《E蹋 ∨场(2)這一限制不鼓勵我們使用改變外部變量的典型命令式編程模式。
final?int?num = 1;
Converter<Integer, String> stringConverter =
????????(from) -> String.valueOf(from + num);
stringConverter.convert(2);
6丙唧、Date Api更新
1.8之前JDK自帶的日期處理類非常不方便,我們處理的時候經(jīng)常是使用的第三方工具包艇棕,比如commons-lang包等。不過1.8出現(xiàn)之后這個改觀了很多沼琉,比如日期時間的創(chuàng)建、比較打瘪、調(diào)整、格式化闺骚、時間間隔等。這些類都在java.time包下僻爽。比原來實用了很多。
6.1LocalDate/LocalTime/LocalDateTime
LocalDate為日期處理類胸梆、LocalTime為時間處理類、LocalDateTime為日期時間處理類碰镜,方法都類似,具體可以看API文檔或源碼绪颖,選取幾個代表性的方法做下介紹。
now相關(guān)的方法可以獲取當(dāng)前日期或時間柠横,of方法可以創(chuàng)建對應(yīng)的日期或時間,parse方法可以解析日期或時間滓鸠,get方法可以獲取日期或時間信息,with方法可以設(shè)置日期或時間信息糜俗,plus或minus方法可以增減日期或時間信息;
6.2TemporalAdjusters
? 這個類在日期調(diào)整時非常有用珠月,比如得到當(dāng)月的第一天、最后一天啤挎,當(dāng)年的第一天、最后一天庆聘,下一周或前一周的某天等。
? 6.3DateTimeFormatter
? 以前日期格式化一般用SimpleDateFormat類伙判,但是不怎么好用黑忱,現(xiàn)在1.8引入了DateTimeFormatter類宴抚,默認(rèn)定義了很多常量格式(ISO打頭的)甫煞,在使用的時候一般配合LocalDate/LocalTime/LocalDateTime使用,比如想把當(dāng)前日期格式化成yyyy-MM-dd hh:mm:ss的形式:
LocalDateTime dt = LocalDateTime.now(); ?
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"); ????????
System.out.println(dtf.format(dt));
7抚吠、流
定義:流是Java API的新成員常潮,它允許我們以聲明性方式處理數(shù)據(jù)集合(通過查詢語句來表達(dá),而不是臨時編寫一個實現(xiàn))楷力。就現(xiàn)在來說蕊玷,我們可以把它們看成遍歷數(shù)據(jù)集的高級迭代器弥雹。此外,流還可以透明地并行處理贸诚,也就是說我們不用寫多線程代碼了厕吉。
Stream 不是集合元素头朱,它不是數(shù)據(jù)結(jié)構(gòu)并不保存數(shù)據(jù),它是有關(guān)算法和計算的班眯,它更像一個高級版本的 Iterator。原始版本的 Iterator宠能,用戶只能顯式地一個一個遍歷元素并對其執(zhí)行某些操作磁餐;高級版本的 Stream,用戶只要給出需要對其包含的元素執(zhí)行什么操作羞延,比如 “過濾掉長度大于 10 的字符串”脾还、“獲取每個字符串的首字母”等,Stream 會隱式地在內(nèi)部進(jìn)行遍歷赛蔫,做出相應(yīng)的數(shù)據(jù)轉(zhuǎn)換泥张。
Stream 就如同一個迭代器(Iterator)渗钉,單向钞钙,不可往復(fù)芒炼,數(shù)據(jù)只能遍歷一次,遍歷過一次后即用盡了鲸湃,就好比流水從面前流過子寓,一去不復(fù)返斜友。而和迭代器又不同的是,Stream 可以并行化操作烹看,迭代器只能命令式地听系、串行化操作虹菲。顧名思義,當(dāng)使用串行方式去遍歷時浪漠,每個 item 讀完后再讀下一個 item址愿。而使用并行去遍歷時冻璃,數(shù)據(jù)會被分成多個段省艳,其中每一個都在不同的線程中處理,然后將結(jié)果一起輸出跋炕。Stream 的并行操作依賴于 Java7 中引入的 Fork/Join 框架(JSR166y)來拆分任務(wù)和加速處理過程辐烂。
流的操作類型分為兩種:
[if !supportLists]·?[endif]Intermediate:一個流可以后面跟隨零個或多個 intermediate 操作纠修。其目的主要是打開流,做出某種程度的數(shù)據(jù)映射/過濾了牛,然后返回一個新的流德召,交給下一個操作使用上岗。這類操作都是惰性化的(lazy)肴掷,就是說背传,僅僅調(diào)用到這類方法径玖,并沒有真正開始流的遍歷颤介。
[if !supportLists]·?[endif]Terminal:一個流只能有一個 terminal 操作滚朵,當(dāng)這個操作執(zhí)行后,流就被使用“光”了韵吨,無法再被操作归粉。所以這必定是流的最后一個操作糠悼。Terminal 操作的執(zhí)行芽狗,才會真正開始流的遍歷童擎,并且會生成一個結(jié)果顾复,或者一個 side effect芯砸。
? 在對于一個 Stream 進(jìn)行多次轉(zhuǎn)換操作 (Intermediate 操作)假丧,每次都對 Stream 的每個元素進(jìn)行轉(zhuǎn)換包帚,而且是執(zhí)行多次,這樣時間復(fù)雜度就是 N(轉(zhuǎn)換次數(shù))個 for 循環(huán)里把所有操作都做掉的總和嗎拘哨?其實不是這樣的倦青,轉(zhuǎn)換操作都是 lazy 的产镐,多個轉(zhuǎn)換操作只會在 Terminal 操作的時候融合起來磷账,一次循環(huán)完成吼鱼。我們可以這樣簡單的理解菇肃,Stream 里有個操作函數(shù)的集合蟆技,每次轉(zhuǎn)換操作就是把轉(zhuǎn)換函數(shù)放入這個集合中质礼,在 Terminal 操作的時候循環(huán) Stream 對應(yīng)的集合织阳,然后對每個元素執(zhí)行所有的函數(shù)眶蕉。
構(gòu)造流的幾種方式:
// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();