1、概述
1.1 为什么要学习java8
java8可以让我们编写更为简洁的代码
1.1.1 【示例1】lambda表达式
-
普通写法
普通写法 -
java8 lambda表达式写法
1.1.2 【示例2】stream的使用
- 普通写法
- java8写法
1.1.3 【示例3】filter使用
- 普通写法
- 行为参数化,把代码传统给方法
1.2 java8支持的一些新特性
- Lambdas表达式
- 方法引用
- 默认方法
- Stream API
- Date Time API
1.3 函数式编程
函数式编程是一种编程范式,所谓编程范式是指一种编程风格
1.3.1 常见的编程范式
-
指令式编程
是一种描述电脑所需作出的行为的编程典范
-
结构化编程
采用子程序、块结构、for循环以及while循环等结构进行编程
-
过程式编程
派生自结构化编程,主要采取程序调用(procedure call)或函数调用(function call)的方式来进行流程控制
-
面向对象编程
一切皆对象
-
函数式编程
在函数式编程中,函数是第一类对象,意思是说一个函数,既可以作为其它函数的参数(输入值),也可以从函数中返回(输入值),被修改或者被分配给一个变量
1.3.2 java8中的函数式编程
在函数式编程出现之前,编程的整个目的在于操作值,值是一等公民。
筛选隐藏文件而函数式编程将方法也提升为一等公民,让编程更简单。将方法引用File::isHidden作为参数传递给listFiles
将方法引用File::isHidden作为参数传递给listFiles 两种方式对比一言以蔽之,函数式编程只是一种编程思想,核心是函数是一等公民,而Java8是利用lambda表达式、方法引用等新特性,将函数式编程的思想引入到了Java中
1.4 为什么要变化
害怕被其他语言替代
1.4.1 java版本历史
从java版本历史来看,java更新缓慢
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
kotlinjava上定义一个类
java上定义一个类
kotlin上定义一个类
kotlin上定义一个类
kotlin推动着java发展,JDK15(2020年9月)推出了Records新特性,也可以达到简写类的目的
Point类
record Point(int x, int y) { }
2. lambda表达式
2.1 什么是lambda表达式
2.1.1 定义
- Lambda表达式是一个匿名函数,即没有函数名的函数
- 可以把函数作为参数传递给方法
- 让代码更简洁
-
lambda表达式由参数、箭头和主体组成
lambda表达式
由参数、箭头和主体组成
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接口只有一个抽象方法,因此它是一个函数式接口
Runnable接口只有一个抽象方法
-
可以按照lambda的语法格式,进行简化
-
调用Runnable的run方法,传入的参数为空,即:()
-
run方法里面的部分,是一个语句,直接copy出来可行了,即:System.out.println("hello lambda")
-
将()和System.out.println("hello lambda");使用->组合起来,得到:() -> System.out.println("hello lambda");
-
最后,将lambda表达式作为参数,传给Thread
new Thread(() -> System.out.println("hello lambda"))
-
如果是多行的情况,就使用{}
new Thread(() -> { System.out.println("hello lambda"); System.out.println("multi-line"); });
-
-
IDEA自动转换功能
IDEA自动转换功能
自动转换
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
-
传入的参数为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是函数式接口
为什么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<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,它允许以声明性的方式处理数据集合
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);
3.2 怎么用
3.2.1 使用流的三个步骤
- 生成流:将list、数组等要操作的数据,转换成流
- 中间操作:filter、map等
- 终端操作:生成一个结果
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<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(); }
-
由函数生成
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
对流中的每一个元素应用函数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
网友评论