Java 8 Lambda 表達(dá)式

2020-09-08 17:33 更新

Java 8 Lambda 表達(dá)式

Java 8 新特性 Java 8 新特性

Lambda 表達(dá)式,也可稱為閉包,它是推動(dòng) Java 8 發(fā)布的最重要新特性。

Lambda 允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)。

使用 Lambda 表達(dá)式可以使代碼變的更加簡(jiǎn)潔緊湊。

語法

lambda 表達(dá)式的語法格式如下:

(parameters) -> expression
或
(parameters) ->{ statements; }

以下是lambda表達(dá)式的重要特征:

  • 可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識(shí)別參數(shù)值。
  • 可選的參數(shù)圓括號(hào):一個(gè)參數(shù)無需定義圓括號(hào),但多個(gè)參數(shù)需要定義圓括號(hào)。
  • 可選的大括號(hào):如果主體包含了一個(gè)語句,就不需要使用大括號(hào)。
  • 可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會(huì)自動(dòng)返回值,大括號(hào)需要指定明表達(dá)式返回了一個(gè)數(shù)值。

lambda表達(dá)式特征

  •  可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識(shí)別參數(shù)值。
  •  可選的參數(shù)圓括號(hào):一個(gè)參數(shù)無需定義圓括號(hào),但多個(gè)參數(shù)需要定義圓括號(hào)。
  •  可選的大括號(hào):如果主體包含了一個(gè)語句,就不需要使用大括號(hào)。
  •  可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會(huì)自動(dòng)返回值,大括號(hào)需要指定明表達(dá)式返回了一個(gè)數(shù)值。

示例:

//入?yún)榭?TestDemo no_param = () -> "hi, no param";
TestDemo no_param2 = () -> { return "hi, no param"; };
System.out.println(no_param.hi());

//單個(gè)參數(shù)
TestDemo2 param = name -> name;
TestDemo2 param2 = name -> { return name;};
System.out.println(param.hei("hei, grils"));

//多個(gè)參數(shù)
TestDemo3 multiple = (String hello, String name) -> hello + " " + name;
//一條返回語句,可以省略大括號(hào)和return
TestDemo3 multiple2 = (hello, name) -> hello + name;
//多條處理語句,需要大括號(hào)和return
TestDemo3 multiple3 = (hello, name) -> {
    System.out.println("進(jìn)入內(nèi)部");
    return hello + name;
};
System.out.println(multiple.greet("hello", "lambda"));

方法引用

有以下幾種類型

3.1 對(duì)象::實(shí)例方法,將 lambda 的參數(shù)當(dāng)做方法的參數(shù)使用

objectName::instanceMethod

示例:

Consumer<String> sc = System.out::println;
//等效
Consumer<String> sc2 = (x) -> System.out.println(x);
sc.accept("618, 狂歡happy");

3.2 類::靜態(tài)方法,將lambda的參數(shù)當(dāng)做方法的參數(shù)使用

ClassName::staticMethod

示例:

//ClassName::staticMethod  類的靜態(tài)方法:把表達(dá)式的參數(shù)值作為staticMethod方法的參數(shù)
Function<Integer, String> sf = String::valueOf;
//等效
Function<Integer, String> sf2 = (x) -> String.valueOf(x);
String apply1 = sf.apply(61888);

3.3 類::實(shí)例方法,將lambda的第一個(gè)參數(shù)當(dāng)做方法的調(diào)用者,其他的參數(shù)作為方法的參數(shù)。開發(fā)中盡量少些此類寫法,減少后續(xù)維護(hù)成本。

ClassName::instanceMethod

示例:

//ClassName::instanceMethod  類的實(shí)例方法:把表達(dá)式的第一個(gè)參數(shù)當(dāng)成instanceMethod的調(diào)用者,其他參數(shù)作為該方法的參數(shù)
BiPredicate<String, String> sbp = String::equals;
//等效
BiPredicate<String, String> sbp2 = (x, y) -> x.equals(y);
boolean test = sbp.test("a", "A");

構(gòu)造函數(shù)

無參的構(gòu)造方法就是類::實(shí)例方法模型,如:

Supplier<User> us = User::new;
//等效
Supplier<User> us2 = () -> new User();
//獲取對(duì)象
User user = us.get();

當(dāng)有參數(shù)時(shí):

//一個(gè)參數(shù),參數(shù)類型不同則會(huì)編譯出錯(cuò)
Function<Integer, User> uf = id -> new User(id);
//或加括號(hào)
Function<Integer, User> uf2 = (id) -> new User(id);
//等效
Function<Integer, User> uf3 = (Integer id) -> new User(id);
User apply = uf.apply(61888);

//兩個(gè)參數(shù)
BiFunction<Integer, String, User> ubf = (id, name) -> new User(id, name);
User 狂歡happy = ubf.apply(618, "狂歡happy");

5、繼承及實(shí)現(xiàn)具有相同默認(rèn)方法的父類或接口問題

接口A:

public interface A {
    String hi();
    String greet();
    default void hello() {
        System.out.println("A.hello");
    }
}

接口B:

public interface B {
    String hi();
    String hh();
    default void hello() {
        System.out.println("B.hello");
    }
}

類C實(shí)現(xiàn)A,B:

public class C implements A, B{

    @Override
    public String hi() {
        return "C.hi";
    }

    @Override
    public String greet() {
        return "C.greet";
    }

    @Override
    public String hh() {
        return "C.hh";
    }

    /**
     * 子類優(yōu)先繼承父類的方法, 如果父類沒有相同簽名的方法,才繼承接口的默認(rèn)方法。
     * 編譯報(bào)錯(cuò)解決1:覆蓋法
     */
    @Override
    public void hello() {
        System.out.println("C.hello");
    }

    /**
     * 編譯報(bào)錯(cuò)解決2:指定實(shí)現(xiàn)的父接口
     */
//    @Override
//    public void hello() {
//        A.super.hello();
////        B.super.hello();
//    }

}

此時(shí)若不處理hello方法時(shí),類C將編譯出錯(cuò),解決方式要么覆蓋,要么指定實(shí)現(xiàn)父接口的該方法。

進(jìn)一步測(cè)試?yán)^承具有相同方法的父類:

類D:

public class D {
    public void hello() {
        System.out.println("D.hello");
    }
}

類 C 繼承類 D:

public class C extends D implements A, B{

    @Override
    public String hi() {
        return "C.hi";
    }

    @Override
    public String greet() {
        return "C.greet";
    }

    @Override
    public String hh() {
        return "C.hh";
    }

}

此時(shí)若不覆蓋或指定父接口的方法時(shí),類C將繼承類D的hello方法。

總結(jié)

java8 引入 lambda 表達(dá)式是接收了函數(shù)式編程語言的思想,例如 scala 之類的,它將函數(shù)視為一等公民,可以使用高階函數(shù)等。

和指令式編程相比,函數(shù)式編程強(qiáng)調(diào)函數(shù)的計(jì)算比指令的執(zhí)行重要。

和過程化編程相比,函數(shù)式編程里函數(shù)的計(jì)算可隨時(shí)調(diào)用。寫在最后,lambda 表達(dá)式可以使代碼看起來簡(jiǎn)潔,但一定程度上增加了代碼的可讀性以及調(diào)試的復(fù)雜性,所以在使用時(shí)應(yīng)盡量是團(tuán)隊(duì)都熟悉使用,要么干脆就別用,不然維護(hù)起來是件較痛苦的事。

Java 8 新特性 Java 8 新特性


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)