Java8初探

1、概述

1.1 為什么要學習java8

java8可以讓我們編寫更為簡潔的代碼

1.1.1 【示例1】lambda表達式

  • 普通寫法

    普通寫法
  • java8 lambda表達式寫法

java8 lambda表達式寫法

1.1.2 【示例2】stream的使用

  • 普通寫法
普通寫法
  • java8寫法
img_17.png

1.1.3 【示例3】filter使用

  • 普通寫法
普通寫法
  • 行為參數(shù)化,把代碼傳統(tǒng)給方法
行為參數(shù)化,把代碼傳統(tǒng)給方法

1.2 java8支持的一些新特性

  • Lambdas表達式
  • 方法引用
  • 默認方法
  • Stream API
  • Date Time API

1.3 函數(shù)式編程

函數(shù)式編程是一種編程范式,所謂編程范式是指一種編程風格

1.3.1 常見的編程范式

  • 指令式編程

    是一種描述電腦所需作出的行為的編程典范

匯編指令
  • 結構化編程

    采用子程序、塊結構、for循環(huán)以及while循環(huán)等結構進行編程

  • 過程式編程

    派生自結構化編程,主要采取程序調(diào)用(procedure call)或函數(shù)調(diào)用(function call)的方式來進行流程控制

  • 面向?qū)ο缶幊?/p>

    一切皆對象

  • 函數(shù)式編程

    在函數(shù)式編程中,函數(shù)是第一類對象,意思是說一個函數(shù),既可以作為其它函數(shù)的參數(shù)(輸入值),也可以從函數(shù)中返回(輸入值),被修改或者被分配給一個變量

1.3.2 java8中的函數(shù)式編程

在函數(shù)式編程出現(xiàn)之前,編程的整個目的在于操作值,值是一等公民。

篩選隱藏文件

而函數(shù)式編程將方法也提升為一等公民,讓編程更簡單。將方法引用File::isHidden作為參數(shù)傳遞給listFiles

將方法引用File::isHidden作為參數(shù)傳遞給listFiles
兩種方式對比

一言以蔽之,函數(shù)式編程只是一種編程思想,核心是函數(shù)是一等公民,而Java8是利用lambda表達式、方法引用等新特性,將函數(shù)式編程的思想引入到了Java中

1.4 為什么要變化

害怕被其他語言替代

1.4.1 java版本歷史

從java版本歷史來看,java更新緩慢

java版本歷史

1.4.2 運行在jvm上的語言

java只是運行在jvm上的其中一種語言。同樣運行在jvm上的還有scala、kotlin等,如果java不持續(xù)更新,就有可能被其他語言給替代掉

運行在jvm上的語言

1.4.3 Martin Odersky(馬丁·奧德斯基)

Martin Odersky馬丁·奧德斯基是函數(shù)式編程的愛好者,他終生一直在JVM平臺上工作。他發(fā)明的第一個語言叫Pizza(1996年),為JVM引入了泛型,并證明了可以在 JVM 平臺上實現(xiàn)函數(shù)式語言特性。
而Scala(2003年)是由他發(fā)明第二種編程語言 ,設計初衷是要集成面向?qū)ο缶幊毯秃瘮?shù)式編程的各種特性,Scala運行于Java虛擬,并兼容現(xiàn)有的Java程序
可以說是Pizza帶來了Java1.5,Scala帶來了Java8

1.4.4 強大的競爭對手kotlin

kotlin

java上定義一個類


java上定義一個類

kotlin上定義一個類


kotlin上定義一個類

kotlin推動著java發(fā)展,JDK15(2020年9月)推出了Records新特性,也可以達到簡寫類的目的


Point類

record Point(int x, int y) { }

2. lambda表達式

2.1 什么是lambda表達式

2.1.1 定義

  • Lambda表達式是一個匿名函數(shù),即沒有函數(shù)名的函數(shù)
  • 可以把函數(shù)作為參數(shù)傳遞給方法
  • 讓代碼更簡潔
  • lambda表達式由參數(shù)、箭頭和主體組成


    lambda表達式

    由參數(shù)、箭頭和主體組成

2.1.2 語法格式

  • 格式

    (parameters) -> expression

    (parameters) -> {statements;}

  • 以下哪些不是lambda表達式

    (1) () -> {}
    (2) () -> "Raoul"
    (3) () -> {return "Mario";}
    (4) (Integer i) -> return "Alan" + i;
    (5) (String s) -> {"IronMan";}
    

2.2 在哪里可以使用以及如何lambda

在函數(shù)式接口上可以使用lambda表達式

2.2.1 什么是函數(shù)式接口

  • 只有一個抽象方法的接口叫做函數(shù)式接口
  • 函數(shù)式接口會使用@FunctionalInterface標注,在編譯時會進行檢查,如果不是函數(shù)式接口就會報錯

2.2.3 以下哪些是函數(shù)式接口?

     public interface Adder{
          int add(int a, int b);
     }
 
     public interface SmartAdder extends Adder{
          int add(double a, double b);
     }
 
     public interface Nothing{
     }

2.2.3 【案例1】為什么Runnbale可以簡寫

為什么Runnbale可以簡寫
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("hello lambda");
    }
};
  • Runnable接口只有一個抽象方法,因此它是一個函數(shù)式接口


    Runnable接口只有一個抽象方法
  • 可以按照lambda的語法格式,進行簡化

    1. 調(diào)用Runnable的run方法,傳入的參數(shù)為空,即:()

    2. run方法里面的部分,是一個語句,直接copy出來可行了,即:System.out.println("hello lambda")

    3. 將()和System.out.println("hello lambda");使用->組合起來,得到:() -> System.out.println("hello lambda");

    4. 最后,將lambda表達式作為參數(shù),傳給Thread

       new Thread(() -> System.out.println("hello lambda"))
      
    5. 如果是多行的情況,就使用{}

         new Thread(() -> {
             System.out.println("hello lambda");
             System.out.println("multi-line");
         });
      
  • IDEA自動轉(zhuǎn)換功能


    IDEA自動轉(zhuǎn)換功能

    自動轉(zhuǎn)換

2.2.4 【案例2】Comparator

  • 按照名字進行排序
  List<Person> list = new ArrayList<>();
  list.add(new Person(18, "Tom"));
  list.add(new Person(6, "Jack"));
  list.add(new Person(20, "Hello"));
  list.add(new Person(17, "Apple"));
  • 編寫compare
  // 按照名字進行排序
  list.sort(new Comparator<Person>() {
      @Override
      public int compare(Person o1, Person o2) {
          return o1.getName().compareTo(o2.getName());
      }
  });
  • 改成lambda

    • 傳入的參數(shù)為o1, 02,寫作(o1, o2)

    • 語句為o1.getName().compareTo(o2.getName())

    • 組合到一起: (o1, o2) -> o1.getName().compareTo(o2.getName())

    • 做為參數(shù)傳給list.sort,得到:list.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));

    • 輸出結果

          Person{age=17, name='Apple'}
          Person{age=20, name='Hello'}
          Person{age=6, name='Jack'}
          Person{age=18, name='Tom'}
      
  • 為什么Comparator是函數(shù)式接口


    為什么Comparator是函數(shù)式接口
為什么Comparator是函數(shù)式接口

2.3 方法引用

2.3.1 什么是方法引用

  • 一種lambda的簡化寫法

    (o1, o2) -> o1.getName().compareTo(o2.getName())
    
    可以簡化為:
    
    Comparator.comparing(Person::getName)
    
  • 格式

    要調(diào)用的類::要調(diào)用類的方法

  • 使用規(guī)則
類型 示例
類名::靜態(tài)方法 Person::sayHello
類名::實例方法 Person::getName
對象::實例方法 comparator::compare
類名::new Person::new
  • 示例

      // 類名::靜態(tài)方法
      list.stream().forEach(Person::sayHello);
    
      // 類名::實例方法
      list.stream().forEach(Person::getName);
    
      // 對象::實例方法
      NameComparator comparator = new NameComparator();
      list.stream().sorted(comparator::compare).forEach(System.out::println);
    
      // 類名::new
      List<String> nameList =  Arrays.asList("Jay", "Tommy", "Helen");
      nameList.stream()
              .map(Person::new)
              .forEach(System.out::println);
    

3. Stream API

3.1 什么是流

3.1.1 基本概念

Stream是Java8的新API,它允許以聲明性的方式處理數(shù)據(jù)集合

3.1.2 什么是聲明性方式

通過查詢語句來表示,而不是臨時編寫一個實現(xiàn)。例如:查詢年齡小于18歲的人的姓名

  • 聲明性方式查詢

    SELECT name FROM persons WHERE age < 18

  • 臨時編寫語句

    for (Person person : list) {
      if (person.getAge() < 18) {
          System.out.println(person.getName());
      }
    }
    
  • Stream的寫法

    list.stream()
      .filter(person -> person.getAge() < 18)
      .map(Person::getName)
      .forEach(System.out::println);
    
Stream

3.2 怎么用

3.2.1 使用流的三個步驟

  • 生成流:將list、數(shù)組等要操作的數(shù)據(jù),轉(zhuǎn)換成流
  • 中間操作:filter、map等
  • 終端操作:生成一個結果
使用流的三個步驟

3.2.2 生成流

  • 由數(shù)組/List創(chuàng)建

      int[] arrays = new int[]{4, 5, 8, 10, 0, -1, 99, -20};
      // 將數(shù)組轉(zhuǎn)換成流
      Arrays.stream(arrays);
      
      List list = Arrays.asList(arrays);
      // 將List轉(zhuǎn)換成流
      list.stream();
    
  • 由值生成

    Stream<String> stream =  Stream.of("a", "bb", "cc");
    
  • 文件生成

      String path = "E:\\Code\\Java8\\src\\com\\test02\\Person.java";
      try (Stream<String> lines = Files.lines(Paths.get(path))) {
          lines.forEach(System.out::println);
      } catch (IOException e) {
          e.printStackTrace();
      }
    
  • 由函數(shù)生成

    Stream.iterate(0, n -> n + 1).forEach(System.out::println);
    

    輸出:

      0
      1
      2
      ... ...
      202687
      202688
      202689
      202690
      202691
      202692
    

    限制值輸出前10個

      Stream.iterate(0, n -> n + 1)
                .limit(10)
                .forEach(System.out::println);
    

3.2.3 終端操作

  • forEach

    int[] arrays = new int[]{4, 5, 8, 10, 0, -1, 99, -20};
    // 終端操作forEach
    Arrays.stream(arrays).forEach(System.out::println);
    
  • count

      // 終端操作count
      long count = Arrays.stream(arrays).count();
      System.out.println(count);
    
  • collect

      List<Integer> list = Stream.iterate(0, n -> n + 1)
              .limit(5)
              .collect(toList());
    

3.2.3 中間操作

1. 篩選

  • filter & distinct
    List<Integer> numbers = Arrays.asList(1, 6, 7, 1, 1, 2, 3, 2, 6);
    numbers.stream()
            .filter(i -> i % 2 == 0)
            .distinct()
            .forEach(System.out::println);

輸出

  6
  2
  • limit & skip
    Stream.iterate(0, n -> n + 1)
    .limit(6)
    .skip(2)
    .forEach(System.out::println);

輸出

    2
    3
    4
    5

2. 映射

  • map
    對流中的每一個元素應用函數(shù)

      List<Person> list = new ArrayList<>();
      list.add(new Person(18, "Tom"));
      list.add(new Person(6, "Jack"));
      list.add(new Person(20, "Hello"));
      list.add(new Person(17, "Apple"));
    
      list.stream()
              .filter(person -> person.getAge() < 18)
              .map(Person::getName)
              .forEach(System.out::println);
    

    輸出

      Jack
      Apple
    
  • flatMap

    flatMap

輸出:

  h
  e
  l
  l
  o
  j
  a
  v
  a
  8

參考

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

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

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