參考傳智視頻,整理中。。。
01_課程介紹
- 重點(diǎn)講解java8 和java9當(dāng)中的新特性
- 課程定位:
適合有一定java編程經(jīng)驗(yàn)的同學(xué),渴望了解最新java前沿技術(shù)的同學(xué),快速入門 - 課程內(nèi)容:
day01 lambda表達(dá)式,函數(shù)式接口、接口更新
day02 方法引用、常用函數(shù)式接口
day03 Stream流式處理api、模塊化
02_Java版本特性更新歷史
| 版本號(hào) | 年份/代號(hào) | 新特性(部分舉例) |
|---|---|---|
| 1.0 | 1996年 | |
| 1.1 | 1997年 | JDBC |
| 1.2 | 1998年 / Playground(運(yùn)動(dòng)場) | 集合、字符串池 |
| 1.3 | 2000年 / Kestrel(美洲紅隼) | JDBC |
| 1.4 | 2004年 / Merlin(灰背隼) | XML、正則、JDBC3.0、斷言、NIO |
| 5.0 | 2004年 / Tigger (老虎) | 泛型、注解、可變參數(shù)、枚舉 |
| 6.0 | 2006年 / Mustang (野馬) | 腳本、JDBC 4.0 |
| 7.0 | 2011年 / Dolphin (海豚) | NIO2.0 、try-with-resources |
| 8.0 | 2014年3月 / Spider (蜘蛛) | 接口更新、lambda表達(dá)式、方法引用、Stream API、函數(shù)式接口、Hashorn、JavaFX、DateTime |
| 9.0 | 2017年9月 | Jigsaw模塊化、Jshell、接口小更新 |
Lambda標(biāo)準(zhǔn)格式
**1.一些參數(shù)
- 一個(gè)箭頭
- 一些代碼**
如果參數(shù)有多個(gè),則使用逗號(hào)分隔; 如果沒有參數(shù),則留空
箭頭是固定寫法
大括號(hào)相當(dāng)于方法體
省略規(guī)則
- 參數(shù)的類型可以省略,但是只能同時(shí)省略所有參數(shù)的類型,或者干脆都不省略,不能致謝個(gè)別參數(shù)的類型
- 如果參數(shù)有且僅有一個(gè),那么小括號(hào)可以省略
- 如果大括號(hào)之內(nèi)的語句有且僅有一個(gè),那么無論有沒有返回值,return、大括號(hào)和分好,都可以省略
03_面向?qū)ο蟮腞unnable接口寫法
public static void main(String[] args) {
//匿名內(nèi)部類對象
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("多線程執(zhí)行?。?!");
}
};
new Thread(runnable).start();
//Lambda表達(dá)式使用
new Thread(() -> System.out.println("111")).start();
}
day01_04_編程思想轉(zhuǎn)換
如何進(jìn)行軟件開發(fā)
- 自己編寫二進(jìn)制
- 匯編語言
- 面向過程
- 面向?qū)ο?/li>
- 函數(shù)式編程思想
面向?qū)ο髲?qiáng)調(diào)“一切皆對象“,如果要想做事情,必須找到對象來做
函數(shù)式編程思想強(qiáng)調(diào)”做什么,而不是怎么做“
05_體驗(yàn)Lambda的更優(yōu)寫法
public static void main(String[] args){
new Thread().start(() -> System.out.println("執(zhí)行了。。。"));
}
06_復(fù)習(xí)并分析匿名內(nèi)部類語法
Lambda分析
Runnable接口當(dāng)中的run方法語義分析
public void run(){
//方法體
}
- 參數(shù)列表為空,不需要任何條件就可以執(zhí)行該方法
- 沒有返回值,方法不產(chǎn)生任何數(shù)據(jù)結(jié)果
- 方法體大括號(hào),這才是關(guān)鍵的方法內(nèi)容所在
() -> System.out.println("線程任務(wù)執(zhí)行”);
- 小括號(hào),不需要任何參數(shù),即可直接執(zhí)行
- 箭頭指向后面要做的事情
- 尖肉后面就好比方法體大括號(hào),代表具體要做的內(nèi)容
07_Lambda表達(dá)式的標(biāo)準(zhǔn)格式
Lambda表達(dá)式的標(biāo)準(zhǔn)格式
三要素:
- 一些參數(shù)
- 一個(gè)箭頭
- 一些代碼
(參數(shù)類型 參數(shù)名稱) -> { 一些代碼}
- 如果參數(shù)有多個(gè),那么使用逗號(hào)分隔,如果參數(shù)沒有,則留空
- 箭頭是固定寫法
- 大括號(hào)相當(dāng)于方法體
08_練習(xí)使用Lambda的標(biāo)準(zhǔn)格式
1、接口 Cook.java
/**
* lambda表達(dá)式的必要前提
* 1. 必須有一個(gè)接口
* 2.接口當(dāng)中必須保證有且有個(gè)抽象方法
*/
public interface Cook {
/*
* 唯一的抽象方法
*/
void makeFood();
}
2、實(shí)現(xiàn)類
public class CookImpl implements Cook {
@Override
public void makeFood() {
System.out.println("makeFood.......");
}
}
3、內(nèi)部類實(shí)現(xiàn)
public class Demo02_InnerClass {
public static void main(String[] args) {
method(new Cook() {
@Override
public void makeFood() {
System.out.println("makeFood...內(nèi)部類實(shí)現(xiàn)。。。");
}
});
}
private static void method(Cook cook){
cook.makeFood();
}
}
public class Demo02_Lambda {
public static void main(String[] args) {
method(() -> System.out.println("makeFood... Lambda實(shí)現(xiàn)方式。。。"));
}
private static void method(Cook cook){
cook.makeFood();
}
}
09_Lambda表達(dá)式的參數(shù)和返回值
1、實(shí)體類
public class Person(){
private String name;
private int age;
//setter/getter、 構(gòu)造方法、toString()省略
}
2、測試類
方式一:
使用匿名內(nèi)部類排序
public class SortTest{
public static void main(String[] args) {
Person[] arrays = {
new Person("劉備", 30),
new Person("張飛", 25),
new Person("張苞", 3),
new Person("關(guān)羽", 27),
};
System.out.println(Arrays.toString(arrays));
Arrays.sort(arrays, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println("-------------------------------------排序后---------------------------------");
System.out.println(Arrays.toString(arrays));
}
方式二:
Lambda方式
public class Demo02_Lambda {
public static void main(String[] args) {
Person[] arrays = {
new Person("劉備", 30),
new Person("張飛", 25),
new Person("張苞", 3),
new Person("關(guān)羽", 27),
};
System.out.println(Arrays.toString(arrays));
Arrays.sort(arrays,(Person o1, Person o2) -> {
return o1.getAge() - o2.getAge();
});
System.out.println("-------------------------------------排序后---------------------------------");
System.out.println(Arrays.toString(arrays));
}
}
10_練習(xí)使用Lambda的參數(shù)和返回值
public interface Calculator {
//兩數(shù)求和
int sum(int a, int b);
}
//測試類
public class CalculatorLambdaTest {
public static void main(String[] args) {
method( (a, b) -> { return a + b ;});
}
private static void method(Calculator calc){
int result = calc.sum(1,2);
System.out.println(result);
}
}
11_Lambda表達(dá)式的省略格式
上面的表達(dá)式可以再簡寫
public class CalculatorLambdaFormat {
public static void main(String[] args) {
// 帶有參數(shù)類型
//1.method( ( int a, int b) -> { return a + b ;});
//省略參數(shù)類型
//2.method( ( a, b) -> { return a + b ;});
//大括號(hào)語句有且只有一個(gè),可省略大括號(hào)、return、分號(hào)
//3.method( (a , b) -> a + b);
method( (a , b) -> a + b);
}
private static void method(Calculator calc){
int result = calc.sum(1,2);
System.out.println(result);
}
}
Lambda表達(dá)式的省略規(guī)則:
1.參數(shù)的類型可以省略,但是只能同時(shí)省略所有參數(shù)的類型,或者干脆都不省略,不能致謝個(gè)別參數(shù)的類型
2.如果參數(shù)有且僅有一個(gè),那么小括號(hào)可以省略
3.如果大括號(hào)之內(nèi)的語句有且僅有一個(gè),那么無論有沒有返回值,return、大括號(hào)和分好,都可以省略
12_練習(xí)使用Lambda的省略格式
/**
* lambda表達(dá)式的必要前提
* 1. 必須有一個(gè)接口
* 2.接口當(dāng)中必須保證有且有個(gè)抽象方法
*/
public interface Cook {
void makeFood();
}
//測試類
public class Demo01_Lambda {
public static void main(String[] args) {
method( () -> System.out.println("makeFood...."));
}
private static void method(Cook cook){
cook.makeFood();
}
}
13_Lambda的使用前提
1.必須保證有一個(gè)接口,而且其中的抽象方法有且僅有一個(gè)
2.必須具有上下文環(huán)境,才能推導(dǎo)出來Lambda對應(yīng)的接口
14_函數(shù)式接口的定義和使用
函數(shù)式接口: 接口當(dāng)中有且僅有一個(gè)抽象方法
@FunctionalInterface注解:用來檢測一個(gè)接口是不是函數(shù)式接口
編譯的時(shí)候,寫上這個(gè)注解:
1.如果是函數(shù)式接口,那么編譯通過。
2.如果不是函數(shù)式接口,那么編譯失敗
注意事項(xiàng):
@FunctionalInterface注解是可選的,就算不用這個(gè)注解,只要保證接口滿足函數(shù)式接口的定義要求,也照樣是函數(shù)式接口
@FunctionalInterface
public interface MyInterface {
void method();
}
15_Lambda與匿名內(nèi)部類的區(qū)別
語法糖
Lambda表達(dá)式并不是匿名內(nèi)部類的“語法糖”
語法糖:代碼的寫法更加簡便,但其實(shí)原理不便。
例如:
1.方法當(dāng)中的可變參數(shù),底層仍然是一個(gè)數(shù)組
2.增強(qiáng)for循環(huán)用于java.lang.Iterable實(shí)現(xiàn)類型時(shí),底層仍然是一個(gè)迭代器
3.自動(dòng)裝箱、自動(dòng)拆箱
Lambda表達(dá)式和匿名內(nèi)部類存在根本區(qū)別,并非語法糖
區(qū)別:
- 所需的類型不一樣
如果是匿名內(nèi)部類,那么用接口、抽象類、普通的類
如果是Lambda表達(dá)式,則必須是接口 - 使用的限制不同
如果接口當(dāng)中有且僅有一個(gè)抽象方法,那么可以使用Lambda表達(dá)式,也可以使用匿名內(nèi)部類
但是如果接口當(dāng)中抽象方法不唯一,則只能使用匿名內(nèi)部類,不能使用Lambda表達(dá)式 - 實(shí)現(xiàn)原理不同
匿名內(nèi)部類,其實(shí)就是一個(gè)類,編譯之后,直接產(chǎn)生一個(gè)單獨(dú)的.class字節(jié)碼文件
Lambda表達(dá)式,編譯之后,沒有單獨(dú)的.class字節(jié)碼文件,對應(yīng)的字節(jié)碼會(huì)再運(yùn)行的時(shí)候才會(huì)動(dòng)態(tài)生成
16_接口的組成部分
- 常量
- 抽象方法
- 默認(rèn)方法 (修飾符default) java8
- 靜態(tài)方法 java8
- 私有方法 java8
17_接口默認(rèn)方法的問題引出
案例1:默認(rèn)方法使用
public interface MyInterface {
void method1();
void method2();
//現(xiàn)在需要重新定義一個(gè)方法,子類MyInterfaceImplA、MyInterfaceImplB都需要實(shí)現(xiàn)
//void methodNew();
}
public class MyInterfaceImplA implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
//重寫接口的抽象方法
@Override
public void methodNew(){
}
}
public class MyInterfaceImplB implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
//重寫接口的抽象方法
@Override
public void methodNew(){
}
}
接口升級(jí):本來是2個(gè)抽象方法,現(xiàn)在需要編程3個(gè)抽象方法
接口的實(shí)現(xiàn)類當(dāng)中必須對接口所有的抽象方法都要覆蓋重寫,除非實(shí)現(xiàn)類是一個(gè)抽象類
根據(jù)設(shè)計(jì)模式當(dāng)中的開閉原則:對擴(kuò)展開放,對修改關(guān)閉
從java8開始,接口當(dāng)中允許定義default默認(rèn)方法
常量的修飾符:public static final (都可以省略)
抽象方法的修飾符:public abstract (都可以省略)
默認(rèn)方法的修飾符:public default void(public可以省略,default不能省略)
可使用java8提供的默認(rèn)方法,解決接口中無須讓各個(gè)實(shí)現(xiàn)類不重寫接口中的抽象方法,使用默認(rèn)方法
public interface MyInterface {
void method1();
void method2();
//現(xiàn)在需要重新定義一個(gè)方法
//void methodNew();
}
public class MyInterfaceImplA implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
}
public class MyInterfaceImplB implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
}
測試方法
public class Demo {
public static void main(String[] args) {
MyInterface myInterface = new MyInterfaceImplA();
//myInterface.method1();
//myInterface.method2();
myInterface.methodNew();
}
}
18_接口默認(rèn)方法的定義和使用
/**
* 接口的實(shí)現(xiàn)類當(dāng)中必須對接口所有的抽象方法都要覆蓋重寫,除非實(shí)現(xiàn)類是一個(gè)抽象類
* 接口升級(jí):本來是2個(gè)抽象方法,現(xiàn)在需要編程3個(gè)抽象方法
*
* 設(shè)計(jì)模式當(dāng)中的開閉原則:對擴(kuò)展開放,對修改關(guān)閉
*
* 從java8開始,接口當(dāng)中允許定義default默認(rèn)方法
* 常量的修飾符:public static final (都可以省略)
* 抽象方法的修飾符:public abstract (都可以省略)
* 默認(rèn)方法的修飾符:public default void(public可以省略,default不能省略)
*
* 默認(rèn)方法可以有方法體實(shí)現(xiàn)
* 默認(rèn)方法也可以進(jìn)行覆蓋重寫,去掉default關(guān)鍵字,重新指定大括號(hào)方法體
*/
public interface MyInterface {
void method1();
void method2()
public default void methodNew(){
System.out.println("默認(rèn)方法");
};
}
public class Demo01 {
public static void main(String[] args) {
MyInterface myInterface = new MyInterfaceImplA();
//myInterface.method1();
//myInterface.method2();
myInterface.methodNew();
}
}
19_接口靜態(tài)方法的定義和使用
public interface Animal{
public abstract void eat();// 抽象方法
public static Animal getAnimal(){
return new Cat();
}
}
public class Cat implements Animal{
public void eat(){
}
}
public class Dog implements Animal{
public void eat(){
}
}
public class Demo{
public static void main(String[] args){
Animal animal = Animal.getAnimal();
animal.eat();
}
}

20_接口靜態(tài)方法在Java9中的應(yīng)用
集合接口的工廠靜態(tài)方法:of
java8 當(dāng)中接口中可以定義的靜態(tài)方法
這個(gè)特性在java9中得以廣泛應(yīng)用
public static void main(String[] args) {
//普通寫法
List<String> list = new ArrayList<>();
list.add("曹操");
list.add("劉備");
list.add("關(guān)羽");
list.add("張飛");
System.out.println(list);
//匿名內(nèi)部類
List<String> list2 = new ArrayList<String>(){
{
add("曹操");
add("劉備");
add("關(guān)羽");
add("張飛");
}
};
System.out.println(list2);
//java 9 寫法
//靜態(tài)
//list
List<String> list3 = List.of("aa","bb","cc","dd");
System.out.println(list3);
//set
Set<String> set = Set.of("aa","bb","cc","dd");
System.out.println(set);
//map
Map<String,Object> map = Map.of("k1","v1");
System.out.println(map);
}
21_接口私有方法的定義和使用
22_接口的組成梳理
在java 9當(dāng)中,定義一個(gè)接口,基本組成都有:
java7或者更老的版本中:
1. 常量:public static final (都可以省略)
2. 抽象方法:public abstract (都可以省略)
java 8 新特性:
- 常量:public static final (都可以省略)
- 抽象方法:public abstract (都可以省略)
3. 默認(rèn)方法:public default (public可以省略,default不能省略,必須有方法體)
4. 靜態(tài)方法:public static (public可以省略,static不能省略,必須有方法體)
java 9 新特性:
- 常量:public static final (都可以省略)
- 抽象方法:public abstract (都可以省略)
- 默認(rèn)方法:public default (public可以省略,default不能省略,必須有方法體)
- 靜態(tài)方法:public static (public可以省略,static不能省略,必須有方法體)
5. 私有方法:
a. 私有的成員方法:private (private 不能省略)
b. 私有的靜態(tài)方法:private static (private static 不能省略)
Lambda表達(dá)式必須有上下文推導(dǎo):
1.根據(jù)調(diào)用方法的參數(shù)推導(dǎo)得知Lambda對應(yīng)的接口
2.根據(jù)局部變量的賦值來推導(dǎo)得知相應(yīng)的接口