Java8新特性

前言:

北京時間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 匯總。

fork/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ù)注解和類型注解陪踩,如下圖:

重復(fù)注解&類型注解

總結(jié):

本文說了一些Java 8 的新特性,重點就是lambda表達(dá)式和Stream API悉抵,可以簡化很多操作肩狂。肯可能還有些文中未涉及的姥饰,在此拋磚引玉傻谁,望各位大佬指點!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末列粪,一起剝皮案震驚了整個濱河市审磁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岂座,老刑警劉巖态蒂,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掺逼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瓤介,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門吕喘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人刑桑,你說我怎么就攤上這事氯质。” “怎么了祠斧?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵闻察,是天一觀的道長。 經(jīng)常有香客問我,道長辕漂,這世上最難降的妖魔是什么呢灶? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮钉嘹,結(jié)果婚禮上鸯乃,老公的妹妹穿的比我還像新娘。我一直安慰自己跋涣,他們只是感情好缨睡,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著陈辱,像睡著了一般奖年。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沛贪,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天陋守,我揣著相機(jī)與錄音,去河邊找鬼鹏浅。 笑死嗅义,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的隐砸。 我是一名探鬼主播之碗,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼季希!你這毒婦竟也來了褪那?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤式塌,失蹤者是張志新(化名)和其女友劉穎博敬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峰尝,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡偏窝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了武学。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祭往。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖火窒,靈堂內(nèi)的尸體忽然破棺而出硼补,到底是詐尸還是另有隱情,我是刑警寧澤熏矿,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布已骇,位于F島的核電站离钝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏褪储。R本人自食惡果不足惜卵渴,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乱豆。 院中可真熱鬧奖恰,春花似錦、人聲如沸宛裕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揩尸。三九已至蛹屿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岩榆,已是汗流浹背错负。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留勇边,地道東北人犹撒。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像粒褒,于是被迫代替她去往敵國和親识颊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容

  • java8新特性 原創(chuàng)者:文思 一奕坟、特性簡介 速度更快 代碼更少祥款,增加了Lambda 強(qiáng)大的Stream API ...
    文思li閱讀 3,032評論 1 1
  • 對于Java開發(fā)者來說,Java8的版本顯然是一個具有里程碑意義的版本月杉,蘊含了許多令人激動的新特性刃跛,如果能利用好這...
    jackcooper閱讀 1,018評論 0 6
  • 對于Java開發(fā)者來說,Java8的版本顯然是一個具有里程碑意義的版本苛萎,蘊含了許多令人激動的新特性桨昙,如果能利用好這...
    huanfuan閱讀 553評論 0 9
  • 原創(chuàng)文章&經(jīng)驗總結(jié)&從校招到A廠一路陽光一路滄桑 詳情請戳www.codercc.com 對于Java開發(fā)者來說,...
    你聽___閱讀 2,337評論 4 38
  • Java 8自Java 5(發(fā)行于2004)以來最具革命性的版本腌歉。Java 8 為Java語言蛙酪、編譯器、類庫究履、開發(fā)...
    huoyl0410閱讀 616評論 1 2