Java Lambda

先來看一個簡單的Lambda用法:java

//多行註釋中爲不使用Lambda的寫法
        /**
        Runnable run = new Runnable() {
            @Override
            public void run() {
                System.out.println("Test")
            }
        };
         */
	   Runnable run = () -> System.out.println("Test");

咱們來看一下Runnable接口:數組

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

####咱們來看一下Java函數式接口【能夠用Lambda方式的接口】的定義: 在Java中,函數式接口是隻定義了一個抽象方法的接口。Java 8引入了FunctionalInterface註解來代表一個接口打算成爲一個函數式接口。在實際使用中無論FunctionalInterface註解是否存在,Java編譯器都會將全部知足該定義的接口看做是函數式接口。 下面咱們本身寫一個接口看一下可否如Runnable通常:app

/**
 * 拿客
 * www.coderknock.com
 * QQ羣:213732117
 * 建立時間:2016年07月22日
 * 描述:
 */
public interface TestLambdaInterface {
    void testInterface();
}

咱們以下使用該接口,程序能正常編譯並輸出結果,說明Java編譯器都會將全部知足該定義的接口看做是函數式接口ide

TestLambdaInterface test=()->System.out.println("Test");
test.testInterface();

#####接口中定義方法的返回值無關性證實: 當咱們將方法的返回值改爲String時:函數

TestLambdaInterface test=()->"test";
        test.testInterface();

說明函數式接口與接口中定義方法的返回值無關 下面咱們在接口中增長一個方法:ui

/**
 * 拿客
 * www.coderknock.com
 * QQ羣:213732117
 * 建立時間:2016年07月22日
 * 描述:
 */
public interface TestLambdaInterface {
    void testInterface();
	void testInterface2();
}

編譯時:code

D:\Work\LearnJavaFX\src>javac -encoding utf-8 LambdaTest.java
LambdaTest.java:20: 錯誤: 不兼容的類型: TestLambdaInterface 不是函數接口
        TestLambdaInterface test = () -> System.out.println("Test");
                                   ^
    在 接口 TestLambdaInterface 中找到多個非覆蓋抽象方法
1 個錯誤

#####default與static方法的無關性證實: 咱們再來看看Java中提供的BinaryOperator接口:對象

package java.util.function;

import java.util.Objects;
import java.util.Comparator;

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {

    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }

    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
}

其實現的接口BiFunction:接口

package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);

    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

該接口可使用以下方法生成實例:圖片

BinaryOperator<Long> add = (x, y) -> x + y;

說明函數式接口與接口中是否存在default與static方法無關 ####總結 充分說明能成爲函數式接口【可使用Lambda來簡化接口操做】的條件爲:只定義了一個抽象方法的接口。

Lambda的幾種寫法

import java.awt.event.ActionListener;
import java.util.function.BinaryOperator;

/**
 * 拿客
 * www.coderknock.com
 * QQ羣:213732117
 * 建立時間:2016年07月22日
 * 描述:
 */
        /**
         * 對於只有一個抽象方法且返回值爲void可使用下面的方法快捷的生成接口的實例
         */
        Runnable voidFunc = () -> System.out.println("沒有參數的函數式接口");
        /**
         * 上面的聲明其實完整寫法應該爲:
         *  Runnable voidFunc = () -> {System.out.println("沒有參數的函數式接口")};
         * 對於只有一行語句時,能夠省略{},
         * 下面是多行語句的狀況,{}不能省略
         */
        Runnable muitiStatement = () -> {
            System.out.println("第一行");
            System.out.println("第二行");
            //多行語句....
        };

        /**
         * 對於有接口中有參數哦的方法咱們可使用
         * ActionListener oneParam = (event) -> System.out.println("一個參數");
         * 當只有一個參數時,能夠省略()以下:
         */
        ActionListener oneParam = event -> System.out.println("一個參數");

        /**
         * 多參數就必須將參數放入到()中調用,按照參數順序寫入
         */
        BinaryOperator<Long> add = (x, y) -> x + y;

        /**
         * 上面幾種狀況中,接口的參數在編譯時進行類型的推斷,咱們亦能夠顯式聲明一下【這樣能夠避免不少錯誤】
         */
        BinaryOperator<Long> add2 = (Long x, Long y) -> x + y;

在Lambda中引用變量需注意的事項

在JDK8對匿名內部類中調用類以外變量必須爲final的限制進行了必定的放寬:

String name = "123";
        Runnable run = new Runnable() {
            @Override
            public void run() {
              	//在JDK8以前下面的語句是會報錯的,只有name是final時纔可使用,可是JDK8中,這樣的語句就不會報錯
                System.out.println(name);
            }
        };

雖然JDK8中上面的語句時能夠的,但這只是減小了咱們代碼中的編寫,編譯時仍是會將name當作是final因此當有如下幾種狀況時,編譯仍是會報錯:

//1.對name進行了第二次賦值,這樣編譯器就會認爲name不是final類型
		String name = "123";
        name="";
        Runnable run = () -> {
            System.out.println(name);
        };
		//2.在匿名類方法中對變量進行賦值也是不容許的
		String name = "123";  
        Runnable run = () -> {
            name="";
            System.out.println(name);
        };

若是真的須要在Lambda中或者匿名中對變量賦值,那麼應該將其放入數組,或者當作一個類的屬性來傳遞【對象final時能夠設置其屬性,不能設置其引用】。 ####IDEA中快速生成Lambda語句 輸入圖片說明

相關文章
相關標籤/搜索