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表達式(重點);
  • 函數(shù)式接口;
  • 方法引用與構(gòu)造器引用;
  • Stream API(重點);
  • 接口中的默認方法與靜態(tài)方法;
  • 新時間日期API;
  • 其他新特性。

有了以上新特性,Java 8就可以做到:

  • 速度更快;
  • 代碼更少(增加了新的語法 Lambda 表達式);
  • 方便操作集合(Stream API)
  • 便于并行;
  • 最大化減少空指針異常 Optional。

接下來一起來了解一下Java 8的這些新特性。


歡迎大家關(guān)注我的公眾號 javawebkf,目前正在慢慢地將簡書文章搬到公眾號,以后簡書和公眾號文章將同步更新,且簡書上的付費文章在公眾號上將免費。


一、Lambada表達式:

1、什么是lambda?
Lambda 是一個匿名函數(shù),我們可以把 Lambda 表達式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進行傳遞)。可以寫出更簡潔、更靈活的代碼。

2、了解新操作符:
Java 8引入了新的操作符,->,叫箭頭操作符或者叫l(wèi)ambda操作符。當(dāng)使用lambda表達式時就需要使用這個操作符。

3、lambda表達式語法:
箭頭操作符將lambda表達式分成了兩部分:

  • 左側(cè):lambda表達式的參數(shù)列表(接口中抽象方法的參數(shù)列表)
  • 右側(cè):lambda表達式中所需執(zhí)行的功能(lambda體,對抽象方法的實現(xiàn))

語法有如下幾種格式:

  • 語法格式一(無參數(shù)無返回值): () -> 具體實現(xiàn)
  • 語法格式二(有一個參數(shù)無返回值): (x) -> 具體實現(xiàn) 或 x -> 具體實現(xiàn)
  • 語法格式三(有多個參數(shù),有返回值,并且lambda體中有多條語句):(x,y) -> {具體實現(xiàn)}
  • 語法格式四:若方法體只有一條語句,那么大括號和return都可以省略
    注:lambda表達式的參數(shù)列表的參數(shù)類型可以省略不寫,可以進行類型推斷。

看幾個例子:
例一:

@Test
public void test1(){
     // 實現(xiàn)一個線程
     int num = 0;//jdk1.8以前,這個必須定義為final,下面才能用,1.8后默認就為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表達式左邊就是(),lambda表達式右邊是抽象方法的實現(xiàn),也就是第一種方式中run方法的方法體寫到lambda表達式右邊就可以了。

例二:

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表達式的簡潔,但是問題來了:我們說lambda表達式就是一個匿名函數(shù),我們只需要指定參數(shù)和lambda體即可,那么它是如何判斷重寫的是哪個方法呢?比如一個接口中有多個方法,如果使用lambda表達式來寫,那么如何判斷我們使用的是該接口的哪個方法?其實是不能判斷的!通過上面兩個例子可以發(fā)現(xiàn),Runnable接口和Comparator接口都是只有一個方法的接口,所以可以使用lambda。

二、函數(shù)式接口:

1、什么是函數(shù)式接口?
像Runnable和Comparator這樣只有一個方法的接口,稱為函數(shù)式接口。也可以在接口上加上@FunctionalInterface注解,如果編譯通過,則該接口就是函數(shù)式接口。lambda表達式就需要函數(shù)式接口的支持。

2、看一個需求:
需求:需要對兩個數(shù)進行加減乘除等運算,怎么實現(xiàn)?

  • 傳統(tǒng)做法:傳統(tǒng)做法中,需要進行幾種運算,我們就要寫幾個方法。一種運算對應(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ù)式接口,不管進行什么操作,都可以用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);//生成隨機數(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)鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。使用Stream API 對集合數(shù)據(jù)進行操作,就類似于使用 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ù)進行處理
  • 終止操作:一個終止操作,執(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,進行加法運算得到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ù),進行拆分(fork)成若干個小任務(wù)(拆到不可再拆時),再將一個個的小任務(wù)運算的結(jié)果進行 join 匯總。

fork/join

2、并行流與串行流:
通過上面的圖可以知道,使用fork/join框架可以提高效率(運算量越大越明顯,運算量可能反而更慢,因為拆分也需要時間),但是在Java 8之前需要自己實現(xiàn)fork/join,還是挺麻煩的,Java 8就方便多了,因為提供了并行流,底層就是使用了fork/join。Stream API 可以聲明性地通過 parallel() 與 sequential() 在并行流與順序流之間進行切換。

@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 時間戳:
時間戳就是計算機讀的時間,它是以Unix元年(傳統(tǒng) 的設(shè)定為UTC時區(qū)1970年1月1日午夜時分)開始算起的。

 //計算機讀的時間:時間戳(Instant),1970年1月1日0時0分0秒到此時的毫秒值
Instant instant = Instant.now();
System.out.println(instant);//默認是美國時區(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);
}

七、接口中的默認方法和靜態(tài)方法:

public interface MyInterface {
    default String test(){
        return "允許存在有具體實現(xiàn)的方法";
    }

    public static String test2(){
        return "接口中還可以有靜態(tài)方法";
    }
}

如上所示,Java 8的接口中允許有默認方法和靜態(tài)方法。如果一個類繼承了一個類還實現(xiàn)了一個接口,而且接口中的默認方法和父類中的方法同名,這時采用類優(yōu)先原則。也就是說,子類使用的是父類的方法,而不是接口中的同名方法。

八、其他新特性:

1、Optional類:
這個類是為了盡可能減少空指針異常的。就是把普通對象用Optional包起來,做了一些封裝??纯雌溆梅ǎ?/p>

@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表達式和Stream API,可以簡化很多操作??峡赡苓€有些文中未涉及的,在此拋磚引玉,望各位大佬指點!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容