1.定義html
百度百科上以下定義: 「Lambda 表達式」(lambda expression)是一個匿名函數,Lambda表達式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。Lambda表達式能夠表示閉包(注意和數學傳統意義上的不一樣)。java
2.java中的Lambdaexpress
java是一個面向對象的語言,而Lambda表達式倒是一個匿名函數,所以java把Lambda表達式抽象成一個匿名內部類(jdk中沒有抽象出來,可是它是一個匿名內部類的實現,在下面的截圖中,很明顯能夠看到是一個內部類的地址----【LambdaTestDemo$lambda@679】)。閉包
爲了證明如上所說,我就隨手寫了一個lambda表達式,來調試一下。app
package com.gcl.jdk8.lambdatest; public class LambdaTestDemo1 { public static void main(String[] args) { //寫一個函數接口指向Lambda表達式,主要爲了看到lambda表達式在傳遞時候的狀態 MyFunctionInterface myFunctionInterface = () -> System.out.println("a"); myFunctionInterface.doSome(); } } @FunctionalInterface interface MyFunctionInterface{ void doSome(); }
在debug狀態下,咱們能夠經過watch清楚的看到lambda表達式是一個內部類。清楚了這一點以後,我想對咱們理解lambda表達式有着重要的幫助 ide
3.基本結構函數
我我的將Lambda表達式分爲3塊,分別是參數模塊,->,代碼塊。相似下面的形式。ui
//真正的表達應該是這樣子的 (param1,param2,...,paramn) -> {code body }
那我就分三塊來講明一下this
a. 參數模塊lua
1.參數類型能夠省略
參數模塊顧名思義,就是表明着傳入Lambda表達式的代碼的參數。通常說來咱們須要定義傳入參數的類型,可是在大部份狀況下,jdk會經過上下文去推斷這個參數是什麼類型,那麼就不須要定義了。下面這塊代碼中,申明 t1的類型的語句能夠省略。我在網上查閱了一些人的博客,他們有的把申明類型的語句留着,我想這樣的作法第一是跟以前的java的寫法保持一致性,第二就是開發的時候雖然jdk能夠本身推斷,可是開發人員若是還要去推斷一下就太麻煩了,大概就是這麼些個理由。
2.()能夠省略
在參數只有1個的時候,()能夠省略。同時也推薦省略。可是若是要申明類型的話,不能省略。
package com.gcl.jdk8.lambdatest; public class LambdaTestDemo1 { public static void main(String[] args) { //寫一個函數接口指向Lambda表達式,主要爲了看到lambda表達式在傳遞時候的狀態 Person p = new Person("張三",12); //MyFunctionInterface<String> myFunctionInterface = (String t1) -> p.setAge(1); MyFunctionInterface<String> myFunctionInterface = t1 -> p.setAge(1); myFunctionInterface.doSome("a"); } } @FunctionalInterface interface MyFunctionInterface<T>{ void doSome(T t); }
b.->
這個沒什麼好說的,寫通常的Lambda表達式必須寫的,這是用來區分參數模塊和代碼模塊的一個標誌,可是在特殊Lambda表達式中也是能夠寫的,在後面我會具體寫一寫這種特殊的Lambda表達式(方法引用)
c.{} 代碼模塊
代碼模塊的具體做用就是處理邏輯的具體實現。 須要注意的是,在具體實現的時候,每一個分之都必須知足其返回值,這也比如是函數,規定了返回值類型,若是某一個分之返回與之不合的返回值類型,那就確定錯了。
//例如在函數接口中規定了返回值是範型T,若是返回了其餘類型的就出錯了 @FunctionalInterface interface MyFunctionInterface<T>{ T doSome(T t); } public static void main(String[] args) { //寫一個函數接口指向Lambda表達式,主要爲了看到lambda表達式在傳遞時候的狀態 Person p = new Person("張三", 12); MyFunctionInterface<String> myFunctionInterface = t1 -> { if (t1.equals("true")) { return "true"; } else { //return Boolean.FALSE; 這樣的返回值就錯了 return "false"; } }; myFunctionInterface.doSome("a"); }
MyFunctionInterface<String> myFunctionInterface2 = t1 -> t1;
注意:
1.單條語句時候,且是表達式語句(expression)的時候{}能夠省略,例如
MyFunctionInterface<String> myFunctionInterface2 = t1 -> t1;
2.單條語句時候,且是return語句(statement)的時候{}能夠不能夠省略,**;**不能夠省略,例如
MyFunctionInterface<String> myFunctionInterface2 = t1 -> {return t1;};
1.定義: 只有一個抽象方法的接口。
定義十分簡單,可是卻有一些比較關鍵的字眼,我抽取其中三個詞:一個,抽象,接口。
一個:只有一個抽象方法,多了不行,少了也不行。同時,這個抽象方法必定不能跟Object類中的方法同名。
/** * 好比說,MyFunctionInterface這個接口,抽象方法是equal方法,其實他是覆蓋了(重寫)Object類中的equals方法。加上@FunctionalInterface註解以後,讓編譯器取作一個顯示檢查是否這個接口只含有一個抽象方法。這樣的接口是一個錯誤的接口示例。 */ @FunctionalInterface interface MyFunctionInterface<T> { //根據阿里巴巴java開發手冊上的規定,若是是重寫的話,強制加上@Override註解 @Override public boolean equals(T t); }
2.配合Lambda表達式的具體使用
一個自定義函數接口,與之對應的Lambda表達式的參數就是這個默認方法的參數,返回值就是這個默認方法的返回值。
@FunctionalInterface interface MyFunctionInterface<String> { String doSome(String t); }
- 五個經常使用的函數接口
java提供的函數接口在java.util.function包中,其中比較重要的是如下5個接口。我認爲jdk8給咱們提供的這些接口是提供了一些模式(幫助咱們抽象出來了一些行爲),在使用的時候根據官方抽象的接口進行實現也更加方便。
a.Consumer (消費模式)
功能:傳遞一個參數,無返回
類定義以下:
package java.util.function; import java.util.Objects; /** * Represents an operation that accepts a single input argument and returns no * result. Unlike most other functional interfaces, {@code Consumer} is expected * to operate via side-effects. * * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #accept(Object)}. * * @param <T> the type of the input to the operation * * @since 1.8 */ @FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * Consumer中的默認方法,表示接受一個參數且沒有返回值 * * @param t the input argument */ void accept(T t); /** * Returns a composed {@code Consumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * 默認方法,提供鏈式調用方式執行。執行流程:先執行自己的accept在執行傳入參數after.accept方法。 * 該方法會拋出NullPointerException異常。 * 若是在執行調用鏈時出現異常,會將異常傳遞給調用鏈功能的調用者,且發生異常後的after將不會在調用。 * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation * @throws NullPointerException if {@code after} is null */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
//隨手寫了一個代碼 package com.gcl.jdk8.lambdatest; import java.util.function.Consumer; public class ConsumerTest { public static void main(String[] args) { //普通的Lambda,表示接受一個參數,void 返回值 Consumer<String> consumer = s -> System.out.println(s); //再簡化一下,特殊的Lambda表達式,方法引用 Consumer<String> consumer2 = System.out::println; //調用一下,狀況如何? consumer.accept("a1"); consumer2.accept("a2"); } }
執行結果以下所示,其實就是一個打印字符串的函數,沒什麼好說的,咱們繼續下一個接口。
b.Supplier (生產模式)
功能:不傳遞參數,返回一個值。咱們來看一下源碼
package java.util.function;
/**
* Represents a supplier of results. * 其實就是不接受任何參數,返回這個接口申明的範型,經過get()來進行調用 * <p>There is no requirement that a new or distinct result be returned each * time the supplier is invoked. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #get()}. * * @param <T> the type of results supplied by this supplier * * @since 1.8 */ @FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
生產者(能夠理解爲,不接受任何參數,返回一個值,究竟返回什麼值由調用者決定----Lambda表達式的製造者)
package com.gcl.jdk8.lambdatest; import java.util.function.Supplier; public class SupplierTest { public static void main(String[] args) { //普通的lambda Supplier<String> supplier1 = () -> "nice"; //特殊的lambda Supplier<String> supplier2 = String::new; String s1 = supplier1.get(); String s2 = supplier2.get(); //打印s1 System.out.println(s1); //打印s2 System.out.println(s2); } }
c.Function (功能模式)
功能:傳遞1個參數,返回1個參數。如今依舊來看一下源碼
package java.util.function; import java.util.Objects; /** * Represents a function that accepts one argument and produces a result. * * 接受一個參數返回一個結果,T是輸入範型,R是輸出範型 * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #apply(Object)}. * * @param <T> the type of the input to the function * @param <R> the type of the result of the function * * @since 1.8 */ @FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); /** * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of input to the {@code before} function, and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function, and of the * composed function * @param after the function to apply after this function is applied * @return a composed function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null * * @see #compose(Function) */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * Returns a function that always returns its input argument. * * @param <T> the type of the input and output objects to the function * @return a function that always returns its input argument */ static <T> Function<T, T> identity() { return t -> t; } }
一樣是舉個例子
package com.gcl.jdk8.lambdatest;
import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { //接受一個值,返回一個Boolean值 Function<Integer,Boolean> function = (i) -> { if(i>1){ return true; } else { return false; } }; Boolean result = function.apply(3); System.out.println(result); } }
在Function<T,R>這個函數式接口中還有着其餘方法【compose】,【andThen】,【identity】,這三個方法其實也是其餘函數式接口中可能存在的方法(在BiFunction這樣的接口中,compose方法是不存在的),對於這樣的方法來講在每一個函數接口中都是有着本身的實現,只不過咱們在讀取源碼以後發現他在每一個函數式接口中的實現都大體類似,所以在Function這個接口中進行一個分析,其餘的接口中就不分析了。
1.compose方法,在javadoc中以下描述。 Returns a composed function that first applies the {@code before},其實很簡單就是一個å前置執行,須要注意的是它傳入的是一個Function接口,返回的也是一個Function接口。
/**
* Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of input to the {@code before} function, and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }
一樣是舉個例子
package com.gcl.jdk8.lambdatest;
import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { //接受一個值,返回一個Boolean值 Function<Integer, Integer> function1 = i -> { if (i > 4) { return 1; } else { return 2; } }; Function<Integer, Integer> function2 = i -> i * i; //在function2執行以前,先執行function1,猜想一下 1小於4返回2,2*2 = 4 Integer integer = function2.compose(function1).apply(1); System.out.println(integer); //在function1執行以前,先執行function2,猜想一下 1*1 = 1 ,比4小返回2 Integer integer2 = function1.compose(function2).apply(1); System.out.println(integer2); } }
2.andThen也很是好理解了,就是一個後置執行,經過一個例子看一下。
package com.gcl.jdk8.lambdatest;
import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { //接受一個值,返回一個Boolean值 Function<Integer, Integer> function1 = i -> { if (i > 4) { return 1; } else { return 2; } }; Function<Integer, Integer> function2 = i -> i * i; //先執行f1,在執行f2,2*2 System.out.println(function1.andThen(function2).apply(1)); //先執行f2,在執行f1,2 -> 1 System.out.println(function2.andThen(function1).apply(1)); } }
3.identity這個靜態方法根據javadoc中的描述,返回的是一個function,返回本身自己。
/**
* Returns a function that always returns its input argument. * * @param <T> the type of the input and output objects to the function * @return a function that always returns its input argument */ static <T> Function<T, T> identity() { return t -> t; }
package com.gcl.jdk8.lambdatest;
import java.util.function.Function; import java.util.function.Supplier; public class FunctionTest { public static void main(String[] args) { //Supplier去返回一個Function的identity方法 Supplier<Function> supplier = Function::identity; //輸出本身 -- t -> t System.out.println(supplier.get().apply(1)); } }
d.Predicate (判斷模式--謂詞)
功能: 傳遞一個參數,返回一個Boolean值。先看javadoc
package java.util.function; import java.util.Objects; /** * Represents a predicate (boolean-valued function) of one argument. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #test(Object)}. * * @param <T> the type of the input to the predicate * * @since 1.8 */ @FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); /** * Returns a composed predicate that represents a short-circuiting logical * AND of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code false}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ANDed with this * predicate * @return a composed predicate that represents the short-circuiting logical * AND of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** * Returns a predicate that represents the logical negation of this * predicate. * * @return a predicate that represents the logical negation of this * predicate */ default Predicate<T> negate() { return (t) -> !test(t); } /** * Returns a composed predicate that represents a short-circuiting logical * OR of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code true}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ORed with this * predicate * @return a composed predicate that represents the short-circuiting logical * OR of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } /** * Returns a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)}. * * @param <T> the type of arguments to the predicate * @param targetRef the object reference with which to compare for equality, * which may be {@code null} * @return a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)} */ static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
我在例子中寫了一個predicate和一個function,能夠看出,pedicate就是一個具體化的function,它規定了它的出參爲boolean,爲了證明個人想法,我翻閱了java核心技術卷I,第240頁,在Predicate的描述中寫到,布爾值的函數。固然他也有一個或操做和一些與操做,感興趣的小夥伴能夠去試一下。
package com.gcl.jdk8.lambdatest;
import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; public class FunctionTest { public static void main(String[] args) { Predicate<Integer> predicate = integer -> { if (integer > 3){ return true; } else { return false; } }; Function<Integer,Boolean> function = integer -> { if (integer > 3){ return true; } else { return false; } }; } }
e.BiXXXX (BiFunction爲例)
功能: 傳遞兩個個參數,獲得一個返回值。
import java.util.Objects;
/**
* Represents a function that accepts two arguments and produces a result. * This is the two-arity specialization of {@link Function}. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #apply(Object, Object)}. * * @param <T> the type of the first argument to the function * @param <U> the type of the second argument to the function * @param <R> the type of the result of the function * * @see Function * @since 1.8 */ @FunctionalInterface public interface BiFunction<T, U, R> { /** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u); /** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function, and of the * composed function * @param after the function to apply after this function is applied * @return a composed function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null */ 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)); }
//返回3 public class FunctionTest { public static void main(String[] args) { BiFunction<Integer,Integer,Integer> biFunction= (i1,i2) -> i1+i2; System.out.println(biFunction.apply(1,2)); } }
須要注意的地方是BiFunction沒有compose方法,由於BiFunction須要的是兩個參數,若是有compsose方法的話,那沒有辦法在一個方法返回兩個返回值。
Lambda表達式和函數式接口分享暫時結束,文章中可能有我理解錯誤的地方,歡迎你們指正,若是須要分享的話請註明出處,下一次分享就是java8中的流操做。