java8 - java9 新特性 (一)

參考傳智視頻,整理中。。。

01_課程介紹

  1. 重點(diǎn)講解java8 和java9當(dāng)中的新特性
  2. 課程定位:
    適合有一定java編程經(jīng)驗(yàn)的同學(xué),渴望了解最新java前沿技術(shù)的同學(xué),快速入門
  3. 課程內(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ù)

  1. 一個(gè)箭頭
  2. 一些代碼**

如果參數(shù)有多個(gè),則使用逗號(hào)分隔; 如果沒有參數(shù),則留空
箭頭是固定寫法
大括號(hào)相當(dāng)于方法體

省略規(guī)則

  1. 參數(shù)的類型可以省略,但是只能同時(shí)省略所有參數(shù)的類型,或者干脆都不省略,不能致謝個(gè)別參數(shù)的類型
  2. 如果參數(shù)有且僅有一個(gè),那么小括號(hào)可以省略
  3. 如果大括號(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ā)

  1. 自己編寫二進(jìn)制
  2. 匯編語言
  3. 面向過程
  4. 面向?qū)ο?/li>
  5. 函數(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(){
        //方法體
}
  1. 參數(shù)列表為空,不需要任何條件就可以執(zhí)行該方法
  2. 沒有返回值,方法不產(chǎn)生任何數(shù)據(jù)結(jié)果
  3. 方法體大括號(hào),這才是關(guān)鍵的方法內(nèi)容所在
() -> System.out.println("線程任務(wù)執(zhí)行”);
  1. 小括號(hào),不需要任何參數(shù),即可直接執(zhí)行
  2. 箭頭指向后面要做的事情
  3. 尖肉后面就好比方法體大括號(hào),代表具體要做的內(nèi)容

07_Lambda表達(dá)式的標(biāo)準(zhǔn)格式

Lambda表達(dá)式的標(biāo)準(zhǔn)格式
三要素:

  1. 一些參數(shù)
  2. 一個(gè)箭頭
  3. 一些代碼

(參數(shù)類型 參數(shù)名稱) -> { 一些代碼}

  1. 如果參數(shù)有多個(gè),那么使用逗號(hào)分隔,如果參數(shù)沒有,則留空
  2. 箭頭是固定寫法
  3. 大括號(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ū)別:

  1. 所需的類型不一樣
    如果是匿名內(nèi)部類,那么用接口、抽象類、普通的類
    如果是Lambda表達(dá)式,則必須是接口
  2. 使用的限制不同
    如果接口當(dāng)中有且僅有一個(gè)抽象方法,那么可以使用Lambda表達(dá)式,也可以使用匿名內(nèi)部類
    但是如果接口當(dāng)中抽象方法不唯一,則只能使用匿名內(nèi)部類,不能使用Lambda表達(dá)式
  3. 實(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_接口的組成部分

  1. 常量
  2. 抽象方法
  3. 默認(rèn)方法 (修飾符default) java8
  4. 靜態(tài)方法 java8
  5. 私有方法 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();
    }
}
image.png

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 新特性:

  1. 常量:public static final (都可以省略)
  2. 抽象方法:public abstract (都可以省略)
    3. 默認(rèn)方法:public default (public可以省略,default不能省略,必須有方法體)
    4. 靜態(tài)方法:public static (public可以省略,static不能省略,必須有方法體)

java 9 新特性:

  1. 常量:public static final (都可以省略)
  2. 抽象方法:public abstract (都可以省略)
  3. 默認(rèn)方法:public default (public可以省略,default不能省略,必須有方法體)
  4. 靜態(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)的接口

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

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

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