在上一篇文章中我們介紹了JDK1.8的新特性有以下幾項,
1.Lambda運算式
2.方法參考
3.函式式介面
4.默認方法
5.Stream
6.Optional類
7.Nashorm javascript引擎
8.新的日期時間API
9.Base64
之前學習了前面兩項Lambda運算式,方法參考,這一篇學習函式式介面,
所謂的函式式介面它只能定義一個抽象方法,其他方法可以用default或者static關鍵對方法進行限定,
下面先來通過實體來驗證一下,
自定義一個函式式介面,然后定義一個叫testA的抽象方法,再定義一個叫testB的抽象方法,

此時@FunctionalInterface注解會提示如下錯誤,(在介面中發現有復數個沒有被覆寫的抽象方法)

那我接下來把testB改為非抽象方法試試,

發現改完之后又多了一處錯誤,我們繼續看看新出的錯誤,

接下來我們把方法加上default關鍵字

這時候就沒有錯誤資訊啦,說明函式式介面中可以除了含有抽象方法外可以有默認的非靜態方法,
下面我把default改成static試一試看看可不可以有靜態方法,

此時發現也沒有問題,那就說明函式式介面中還可以有靜態方法,
因為Object類是所有類的父類,所有介面中能被重寫的方法都可以在介面中定義,比如
toString,equals方法,

了解完函式式介面,接下來說一下API內置的四大函式式介面,
主要就以下
1. Consumer -- 消費性介面
2. Supplier -- 供給型介面
3. Function -- 函式型介面
4. Predicate -- 斷言型介面
下面我們依次來看一下API源代碼,以及通過寫實體來理解一下每種型別介面使用方法以及特點,
1. Consumer(有傳入,沒有傳出的時候使用)
官方源代碼如下,為了起來方便簡潔把開頭的注釋去掉了,只保留了方法的注釋,
1 package java.util.function; 2 3 import java.util.Objects; 4 5 @FunctionalInterface 6 public interface Consumer<T> { 7 8 /** 9 * Performs this operation on the given argument. 10 * 11 * @param t the input argument 12 */ 13 void accept(T t); 14 15 /** 16 * Returns a composed {@code Consumer} that performs, in sequence, this 17 * operation followed by the {@code after} operation. If performing either 18 * operation throws an exception, it is relayed to the caller of the 19 * composed operation. If performing this operation throws an exception, 20 * the {@code after} operation will not be performed. 21 * 22 * @param after the operation to perform after this operation 23 * @return a composed {@code Consumer} that performs in sequence this 24 * operation followed by the {@code after} operation 25 * @throws NullPointerException if {@code after} is null 26 */ 27 default Consumer<T> andThen(Consumer<? super T> after) { 28 Objects.requireNonNull(after); 29 return (T t) -> { accept(t); after.accept(t); }; 30 } 31 }
直接看accept抽象方法,接收一個泛型T型別的t,回傳值型別是void,我們把它叫做消費型介面,特點就是有去無回,
下面我們直接看實體
1 public class InfixFunctionTest { 2 //1.消費型介面 3 @Test 4 public void test1(){ 5 //把傳入的字串列印 6 Consumer<String> con = x -> System.out.println(x);//定義函式式的實作 7 con.accept("Hello Consumer!");//接收引數 8 } 9 10 }
執行結果
com.dream.test.JDK8speciality.InfixFunctionTest,test1 Hello Consumer! Process finished with exit code 0
我們只需要在Lambda運算式的引數串列中傳入一個x,然后實作是:得到一個無回傳型別的列印陳述句,
2. Supplier(沒有傳入,有傳出的時候使用)
官方原始碼
1 package java.util.function; 2 3 /** 4 * Represents a supplier of results. 5 * 6 * <p>There is no requirement that a new or distinct result be returned each 7 * time the supplier is invoked. 8 * 9 * <p>This is a <a href="https://www.cnblogs.com/worthycoder/p/package-summary.html">functional interface</a> 10 * whose functional method is {@link #get()}. 11 * 12 * @param <T> the type of results supplied by this supplier 13 * 14 * @since 1.8 15 */ 16 @FunctionalInterface 17 public interface Supplier<T> { 18 19 /** 20 * Gets a result. 21 * 22 * @return a result 23 */ 24 T get(); 25 }
get方法沒有傳入引數,回傳一個T,稱為供給型介面,特點就是只求回報不求付出,
實體
1 public class InfixFunctionTest { 2 3 //2.供給型介面 4 @Test 5 public void test2(){ 6 Supplier<String> su = () -> new String(); 7 String str = su.get(); 8 System.out.println("供給型介面的值:" + str); 9 } 10 11 }
執行結果
com.dream.test.JDK8speciality.InfixFunctionTest,test2
供給型介面的值:
Process finished with exit code 0
我們在Lambda運算式傳入引數用()代表沒有引數傳入,然后回傳一個String型別的物件,
3.Function(有傳入引數,傳出的時候使用)
官方原始碼
1 package java.util.function; 2 3 import java.util.Objects; 4 5 /** 6 * Represents a function that accepts one argument and produces a result. 7 * 8 * <p>This is a <a href="https://www.cnblogs.com/worthycoder/p/package-summary.html">functional interface</a> 9 * whose functional method is {@link #apply(Object)}. 10 * 11 * @param <T> the type of the input to the function 12 * @param <R> the type of the result of the function 13 * 14 * @since 1.8 15 */ 16 @FunctionalInterface 17 public interface Function<T, R> { 18 19 /** 20 * Applies this function to the given argument. 21 * 22 * @param t the function argument 23 * @return the function result 24 */ 25 R apply(T t); 26 27 /** 28 * Returns a composed function that first applies the {@code before} 29 * function to its input, and then applies this function to the result. 30 * If evaluation of either function throws an exception, it is relayed to 31 * the caller of the composed function. 32 * 33 * @param <V> the type of input to the {@code before} function, and to the 34 * composed function 35 * @param before the function to apply before this function is applied 36 * @return a composed function that first applies the {@code before} 37 * function and then applies this function 38 * @throws NullPointerException if before is null 39 * 40 * @see #andThen(Function) 41 */ 42 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { 43 Objects.requireNonNull(before); 44 return (V v) -> apply(before.apply(v)); 45 } 46 47 /** 48 * Returns a composed function that first applies this function to 49 * its input, and then applies the {@code after} function to the result. 50 * If evaluation of either function throws an exception, it is relayed to 51 * the caller of the composed function. 52 * 53 * @param <V> the type of output of the {@code after} function, and of the 54 * composed function 55 * @param after the function to apply after this function is applied 56 * @return a composed function that first applies this function and then 57 * applies the {@code after} function 58 * @throws NullPointerException if after is null 59 * 60 * @see #compose(Function) 61 */ 62 default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { 63 Objects.requireNonNull(after); 64 return (T t) -> after.apply(apply(t)); 65 } 66 67 /** 68 * Returns a function that always returns its input argument. 69 * 70 * @param <T> the type of the input and output objects to the function 71 * @return a function that always returns its input argument 72 */ 73 static <T> Function<T, T> identity() { 74 return t -> t; 75 } 76 }
Function介面提供了一個抽象方法,兩個默認方法和一個靜態方法,這里我只對最常用的抽象方法做出解釋,
apply方法接收一個T型別的t,回傳一個R型別的值,我們稱之為函式型介面,特點就是你來我往,(俗話說的好,來而不往非禮也!哈哈哈!)
實體
1 public class InfixFunctionTest { 2 3 //3.函式型介面 4 @Test 5 public void test3(){ 6 Function<String,Camera> fun = (x) -> new Camera(x);//Function抽象函式的實作, 7 Camera camera = fun.apply("Sony-A7R3");//接收傳入的引數 8 System.out.println("cameraName: " + camera.getCameraName() + " price:" + camera.getPrice()); 9 } 10 11 }
Camera類
1 //相機類 2 class Camera{ 3 //相機名字 4 private String cameraName; 5 //相機價格 6 private Integer price; 7 8 //無引數構造器 9 public Camera(){ 10 11 } 12 13 //有引數構造器 14 public Camera(String cameraName){ 15 this.cameraName = cameraName; 16 } 17 18 //有引數構造器 19 public Camera(String cameraName,Integer price){ 20 this.cameraName = cameraName; 21 this.price = price; 22 } 23 24 public String getCameraName() { 25 return cameraName; 26 } 27 28 public void setCameraName(String cameraName) { 29 this.cameraName = cameraName; 30 } 31 32 public Integer getPrice() { 33 return price; 34 } 35 36 public void setPrice(Integer price) { 37 this.price = price; 38 } 39 }
執行結果
com.dream.test.JDK8speciality.InfixFunctionTest,test3 cameraName: Sony-A7R3 price:null Process finished with exit code 0
Lam運算式中傳入一個引數x,然后x作為構造器的引數,回傳一個Camera物件,
4.Predicate(傳入一個引數,回傳一個布爾型別的結果)
官網原始碼
1 package java.util.function; 2 3 import java.util.Objects; 4 5 /** 6 * Represents a predicate (boolean-valued function) of one argument. 7 * 8 * <p>This is a <a href="https://www.cnblogs.com/worthycoder/p/package-summary.html">functional interface</a> 9 * whose functional method is {@link #test(Object)}. 10 * 11 * @param <T> the type of the input to the predicate 12 * 13 * @since 1.8 14 */ 15 @FunctionalInterface 16 public interface Predicate<T> { 17 18 /** 19 * Evaluates this predicate on the given argument. 20 * 21 * @param t the input argument 22 * @return {@code true} if the input argument matches the predicate, 23 * otherwise {@code false} 24 */ 25 boolean test(T t); 26 27 /** 28 * Returns a composed predicate that represents a short-circuiting logical 29 * AND of this predicate and another. When evaluating the composed 30 * predicate, if this predicate is {@code false}, then the {@code other} 31 * predicate is not evaluated. 32 * 33 * <p>Any exceptions thrown during evaluation of either predicate are relayed 34 * to the caller; if evaluation of this predicate throws an exception, the 35 * {@code other} predicate will not be evaluated. 36 * 37 * @param other a predicate that will be logically-ANDed with this 38 * predicate 39 * @return a composed predicate that represents the short-circuiting logical 40 * AND of this predicate and the {@code other} predicate 41 * @throws NullPointerException if other is null 42 */ 43 default Predicate<T> and(Predicate<? super T> other) { 44 Objects.requireNonNull(other); 45 return (t) -> test(t) && other.test(t); 46 } 47 48 /** 49 * Returns a predicate that represents the logical negation of this 50 * predicate. 51 * 52 * @return a predicate that represents the logical negation of this 53 * predicate 54 */ 55 default Predicate<T> negate() { 56 return (t) -> !test(t); 57 } 58 59 /** 60 * Returns a composed predicate that represents a short-circuiting logical 61 * OR of this predicate and another. When evaluating the composed 62 * predicate, if this predicate is {@code true}, then the {@code other} 63 * predicate is not evaluated. 64 * 65 * <p>Any exceptions thrown during evaluation of either predicate are relayed 66 * to the caller; if evaluation of this predicate throws an exception, the 67 * {@code other} predicate will not be evaluated. 68 * 69 * @param other a predicate that will be logically-ORed with this 70 * predicate 71 * @return a composed predicate that represents the short-circuiting logical 72 * OR of this predicate and the {@code other} predicate 73 * @throws NullPointerException if other is null 74 */ 75 default Predicate<T> or(Predicate<? super T> other) { 76 Objects.requireNonNull(other); 77 return (t) -> test(t) || other.test(t); 78 } 79 80 /** 81 * Returns a predicate that tests if two arguments are equal according 82 * to {@link Objects#equals(Object, Object)}. 83 * 84 * @param <T> the type of arguments to the predicate 85 * @param targetRef the object reference with which to compare for equality, 86 * which may be {@code null} 87 * @return a predicate that tests if two arguments are equal according 88 * to {@link Objects#equals(Object, Object)} 89 */ 90 static <T> Predicate<T> isEqual(Object targetRef) { 91 return (null == targetRef) 92 ? Objects::isNull 93 : object -> targetRef.equals(object); 94 } 95 }
Predicate介面提供了一個抽象方法,三個默認方法和一個靜態方法,這里是對抽象方法進行舉例說明,
由于回傳一個布爾型別的值,我們稱之為斷言型,特點就是發出請求,等待指示(做還是不做,哈哈),
1 public class InfixFunctionTest { 2 3 //4.斷言式介面 4 @Test 5 public void test4(){ 6 Predicate<String> pre = x -> x == null; 7 Boolean b =pre.test(null); 8 System.out.println("斷言式測驗結果:" + b); 9 } 10 11 }
執行結果
com.dream.test.JDK8speciality.InfixFunctionTest,test4 斷言式測驗結果:true Process finished with exit code 0
Lambda運算式傳入一個引數x,判斷x是不是null,
以上實體中都省略了頭部的打包和匯入包資訊,包資訊如下,
1 package com.dream.test.JDK8speciality; 2 3 import org.junit.Test; 4 5 import java.util.function.Consumer; 6 import java.util.function.Function; 7 import java.util.function.Predicate; 8 import java.util.function.Supplier;
java.util.function包下除了上面這幾個基本函式式介面外,還有好多,其他的都是這幾個基本的衍生,這幾個搞懂了,其他的就都不難理解了,有興趣的可以自己進行研究,
以上就是對函式式的學習,如果各位大神發現有不對或者不好的地方,歡迎指正,非常感謝!
上一篇文章
JDK1.8新特性之(二)--方法參考
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/185235.html
標籤:Java
