Java8初探

1、概述

1.1 为什么要学习java8

java8可以让我们编写更为简洁的代码

1.1.1 【示例1】lambda表达式

  • 普通写法

    Java8初探_第1张图片
    普通写法
  • java8 lambda表达式写法

java8 lambda表达式写法

1.1.2 【示例2】stream的使用

  • 普通写法
Java8初探_第2张图片
普通写法
  • java8写法
img_17.png

1.1.3 【示例3】filter使用

  • 普通写法
Java8初探_第3张图片
普通写法
  • 行为参数化,把代码传统给方法
Java8初探_第4张图片
行为参数化,把代码传统给方法

1.2 java8支持的一些新特性

  • Lambdas表达式
  • 方法引用
  • 默认方法
  • Stream API
  • Date Time API

1.3 函数式编程

函数式编程是一种编程范式,所谓编程范式是指一种编程风格

1.3.1 常见的编程范式

  • 指令式编程

    是一种描述电脑所需作出的行为的编程典范

Java8初探_第5张图片
汇编指令
  • 结构化编程

    采用子程序、块结构、for循环以及while循环等结构进行编程

  • 过程式编程

    派生自结构化编程,主要采取程序调用(procedure call)或函数调用(function call)的方式来进行流程控制

  • 面向对象编程

    一切皆对象

  • 函数式编程

    在函数式编程中,函数是第一类对象,意思是说一个函数,既可以作为其它函数的参数(输入值),也可以从函数中返回(输入值),被修改或者被分配给一个变量

1.3.2 java8中的函数式编程

在函数式编程出现之前,编程的整个目的在于操作值,值是一等公民。

Java8初探_第6张图片
筛选隐藏文件

而函数式编程将方法也提升为一等公民,让编程更简单。将方法引用File::isHidden作为参数传递给listFiles

将方法引用File::isHidden作为参数传递给listFiles
Java8初探_第7张图片
两种方式对比

一言以蔽之,函数式编程只是一种编程思想,核心是函数是一等公民,而Java8是利用lambda表达式、方法引用等新特性,将函数式编程的思想引入到了Java中

1.4 为什么要变化

害怕被其他语言替代

1.4.1 java版本历史

从java版本历史来看,java更新缓慢

Java8初探_第8张图片
java版本历史

1.4.2 运行在jvm上的语言

java只是运行在jvm上的其中一种语言。同样运行在jvm上的还有scala、kotlin等,如果java不持续更新,就有可能被其他语言给替代掉

运行在jvm上的语言

1.4.3 Martin Odersky(马丁·奥德斯基)

Martin Odersky马丁·奥德斯基是函数式编程的爱好者,他终生一直在JVM平台上工作。他发明的第一个语言叫Pizza(1996年),为JVM引入了泛型,并证明了可以在 JVM 平台上实现函数式语言特性。
而Scala(2003年)是由他发明第二种编程语言 ,设计初衷是要集成面向对象编程和函数式编程的各种特性,Scala运行于Java虚拟,并兼容现有的Java程序
可以说是Pizza带来了Java1.5,Scala带来了Java8

1.4.4 强大的竞争对手kotlin

Java8初探_第9张图片
kotlin

java上定义一个类


Java8初探_第10张图片
java上定义一个类

kotlin上定义一个类


kotlin上定义一个类

kotlin推动着java发展,JDK15(2020年9月)推出了Records新特性,也可以达到简写类的目的


Java8初探_第11张图片
Point类

record Point(int x, int y) { }

2. lambda表达式

2.1 什么是lambda表达式

2.1.1 定义

  • Lambda表达式是一个匿名函数,即没有函数名的函数
  • 可以把函数作为参数传递给方法
  • 让代码更简洁
  • lambda表达式由参数、箭头和主体组成


    lambda表达式

    Java8初探_第12张图片
    由参数、箭头和主体组成

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

在函数式接口上可以使用lambda表达式

2.2.1 什么是函数式接口

  • 只有一个抽象方法的接口叫做函数式接口
  • 函数式接口会使用@FunctionalInterface标注,在编译时会进行检查,如果不是函数式接口就会报错

2.2.3 以下哪些是函数式接口?

     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接口只有一个抽象方法,因此它是一个函数式接口


    Java8初探_第13张图片
    Runnable接口只有一个抽象方法
  • 可以按照lambda的语法格式,进行简化

    1. 调用Runnable的run方法,传入的参数为空,即:()

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

    3. 将()和System.out.println("hello lambda");使用->组合起来,得到:() -> System.out.println("hello lambda");

    4. 最后,将lambda表达式作为参数,传给Thread

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

         new Thread(() -> {
             System.out.println("hello lambda");
             System.out.println("multi-line");
         });
      
  • IDEA自动转换功能


    Java8初探_第14张图片
    IDEA自动转换功能

    自动转换

2.2.4 【案例2】Comparator

  • 按照名字进行排序
  List 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() {
      @Override
      public int compare(Person o1, Person o2) {
          return o1.getName().compareTo(o2.getName());
      }
  });
  • 改成lambda

    • 传入的参数为o1, 02,写作(o1, o2)

    • 语句为o1.getName().compareTo(o2.getName())

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

    • 做为参数传给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是函数式接口


    Java8初探_第15张图片
    为什么Comparator是函数式接口
Java8初探_第16张图片
为什么Comparator是函数式接口

2.3 方法引用

2.3.1 什么是方法引用

  • 一种lambda的简化写法

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

    要调用的类::要调用类的方法

  • 使用规则
类型 示例
类名::静态方法 Person::sayHello
类名::实例方法 Person::getName
对象::实例方法 comparator::compare
类名::new Person::new
  • 示例

      // 类名::静态方法
      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 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,它允许以声明性的方式处理数据集合

3.1.2 什么是声明性方式

通过查询语句来表示,而不是临时编写一个实现。例如:查询年龄小于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);
    
Java8初探_第17张图片
Stream

3.2 怎么用

3.2.1 使用流的三个步骤

  • 生成流:将list、数组等要操作的数据,转换成流
  • 中间操作:filter、map等
  • 终端操作:生成一个结果
Java8初探_第18张图片
使用流的三个步骤

3.2.2 生成流

  • 由数组/List创建

      int[] arrays = new int[]{4, 5, 8, 10, 0, -1, 99, -20};
      // 将数组转换成流
      Arrays.stream(arrays);
      
      List list = Arrays.asList(arrays);
      // 将List转换成流
      list.stream();
    
  • 由值生成

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

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

    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 list = Stream.iterate(0, n -> n + 1)
              .limit(5)
              .collect(toList());
    

3.2.3 中间操作

1. 筛选

  • filter & distinct
    List 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
    对流中的每一个元素应用函数

      List 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

    Java8初探_第19张图片
    flatMap

输出:

  h
  e
  l
  l
  o
  j
  a
  v
  a
  8

参考

  • Java8实战
  • Java版本历史
  • 为什么说 Scala 是 JVM 上的 C++?
  • 尚硅谷Scala教程
  • kotlin维基百科
  • 在大型团队中采用 Kotlin
  • Java正在“Kotlin化”
  • JDK15 Records新特性
  • java Comparator为何是函数式接口?
  • Method References in Java

你可能感兴趣的:(Java8初探)