1、概述
1.1 為什么要學習java8
java8可以讓我們編寫更為簡潔的代碼
1.1.1 【示例1】lambda表達式
-
普通寫法
普通寫法 java8 lambda表達式寫法

1.1.2 【示例2】stream的使用
- 普通寫法

- java8寫法

1.1.3 【示例3】filter使用
- 普通寫法

- 行為參數(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


一言以蔽之,函數(shù)式編程只是一種編程思想,核心是函數(shù)是一等公民,而Java8是利用lambda表達式、方法引用等新特性,將函數(shù)式編程的思想引入到了Java中
1.4 為什么要變化
害怕被其他語言替代
1.4.1 java版本歷史
從java版本歷史來看,java更新緩慢

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

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

java上定義一個類

kotlin上定義一個類

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

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可以簡寫

Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello lambda");
}
};
-
Runnable接口只有一個抽象方法,因此它是一個函數(shù)式接口
Runnable接口只有一個抽象方法
-
可以按照lambda的語法格式,進行簡化
調(diào)用Runnable的run方法,傳入的參數(shù)為空,即:()
run方法里面的部分,是一個語句,直接copy出來可行了,即:System.out.println("hello lambda")
將()和System.out.println("hello lambda");使用->組合起來,得到:() -> System.out.println("hello lambda");
-
最后,將lambda表達式作為參數(shù),傳給Thread
new Thread(() -> System.out.println("hello lambda")) -
如果是多行的情況,就使用{}
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ù)式接口

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);

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







