函數式接口
函數式接口詳解:FunctionInterface接口
話不多說,先打開源碼,查閱一番。尋得FunctionInterface接口
package java.util.function;
import java.util.Objects;
/**
* Represents a function that accepts one argument and produces a result.
*
* <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;
}
}
函數式接口代碼測試:FunctionTest
public class FunctionTest {
public static void main(String[] args) {
FunctionTest test = new FunctionTest();
// 傳遞行為,而不是傳遞值
System.out.println(test.comput(1, value -> 2 * value));
System.out.println(test.comput(2, value -> 5 + value));
System.out.println(test.comput(3,Integer::intValue));
System.out.println(test.convert(4,value -> value + "helloworld"));
}
public int comput(int a, Function<Integer, Integer> function) {
//apply ,傳遞的是行為
int result = function.apply(a);
return result;
}
public String convert(int a, Function<Integer, String> function) {
return function.apply(a);
}
// 對於之前只傳遞值的寫法,幾種行為就要定義幾種寫法。 現在可以使用上面的方式去 傳遞行為
public int method1(int a) {
return a + 1;
}
public int method2(int a) {
return a * 5;
}
public int method3(int a) {
return a * a;
}
}
高階函數:如果一個函數接收一個函數作為參數,或者返回一個函數作為返回值,那么該函數就叫做高階函數。函數式編程語言js等語言里面都支持大量的高階函數,JAVA從1.8開始也開始支持高階函數。
FunctionInterface接口中提供的方法詳解
- apply
- compose (function組合)
- andThen
- identity
代碼測試上述方法
package java.util.function;
import java.util.Objects;
/**
* Represents a function that accepts one argument and produces a result.
*
* <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
* 先應用beforefunction,再應用實例的function
實際上:將兩個function組合在一起了。先執行before方法,然后將處理的結果傳遞給當前對象的apply方法。實現了兩個function的串聯。既然實現了兩個function的串聯,就能實現多個函數的串聯。
* @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
和before函數相反,先應用this function,然后再使用after方法。 實現兩個方法的串聯。
* @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;
}
}
- compose:
先應用beforefunction,再應用實例的function
實際上:將兩個function組合在一起了。先執行before方法,然后將處理的結果傳遞給當前對象的apply方法。實現了兩個function的串聯。既然實現了兩個function的串聯,就能實現多個函數的串聯。 - andThen:
和before函數相反,先應用this function,然后再使用after方法。 實現兩個方法的串聯。 - identity:
傳入什么,返回什么。
這些方法都是很有價值的。
/**
* compose , andThen 方法的使用
*/
public class FunctionTest2 {
public static void main(String[] args) {
FunctionTest2 test2 = new FunctionTest2();
int compute = test2.compute(2, v -> v * 3, v -> v * v);//12
int compute2 = test2.compute2(2, v -> v * 3, v -> v * v);//36
System.out.println(compute);
System.out.println(compute2);
}
public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
return function1.compose(function2).apply(a);
}
public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
return function1.andThen(function2).apply(a);
}
}
BiFunction類詳解
package java.util.function;
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));
}
}
BiFunction類,雙向接口類,提供了兩個輸入參數,一個輸出參數
//BiFunction類的使用。 有兩個輸入參數
public int compute3(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) {
return biFunction.apply(a, b);
}
public int compute4(int a, int b, BiFunction<Integer, Integer, Integer> biFunction,Function<Integer,Integer> function) {
return biFunction.andThen(function).apply(a,b);
}
//使用BiFunction來完成
System.out.println(test2.compute3(1,2,(value1,value2)-> value1 + value2));
System.out.println(test2.compute3(1,2,(value1,value2)-> value1 - value2));
System.out.println(test2.compute3(1, 2, (value1, value2) -> value1 * value2));
System.out.println(test2.compute3(1, 2, (value1, value2) -> value1 / value2));
//使用BiFunction中的andThen.
System.out.println(test2.compute4(2,3,(value1,value2)->value1+value2,value->value*value));
為什么BiFunction類中沒有Compose方法呢?
倒推一下:因為如果有Compose方法,會先執行參數的Function。無論參數是Function還是BiFunction,返回值也都是一個值,然后就沒辦法再去執行BiFuntion.
使用lambda表達式解決簡單的開發問題:
定義一個簡單的Person類,然后使用lambda表達式解決一些問題
public class Person {
private String username;
private int age;
}
package com.dawa.jdk8;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
public class PersonTest {
public static void main(String[] args) {
Person person1 = new Person("zhangsan", 20);
Person person2 = new Person("lisi", 30);
Person person3 = new Person("wangwu", 40);
List<Person> list = Arrays.asList(person1,person2,person3);
PersonTest test = new PersonTest();
//測試第一個方法。
List<Person> list1 = test.getPersonByUsername("zhangsan", list);
list1.forEach(person -> System.out.println(person.getUsername()));
//測試第二種方法
List<Person> personByAge = test.getPersonByAge(20, list);
personByAge.forEach(person -> System.out.println(person.getAge()));
//測試第三方法
List<Person> peopleList = test.getPersonByArg(20, list,
(age, personList) -> personList.stream().filter(p
erson -> person.getAge() > age).collect(Collectors.toList()));
peopleList.forEach(person -> System.out.println(person.getUsername()));
}
//使用lambda表達式定義一個 處理的方法
//filter 方法,參數是一個Predicate 謂語
//stream 提供了一個將流轉換成集合的方法 collect(Collectors.toList())
public List<Person> getPersonByUsername(String username, List<Person> personList) {
return personList.stream().
filter(person ->
person.getUsername().equals("zhangsan")).collect(Collectors.toList());
}
//第二種方式,先直接使用lambda表達式將BiFunction定義好,然后直接將方法的兩個參數傳入到BiFunction.
public List<Person> getPersonByAge(int age, List<Person> personList) {
BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageArg, Persons) -> {
return Persons.stream().filter(person -> person.getAge() > ageArg).collect(Collectors.toList());
};
return biFunction.apply(age,personList);
}
//第三種方式,動作也讓他自己傳遞。 函數式接口的好處。
public List<Person> getPersonByArg(int age, List<Person> personList, BiFunction<Integer, List<Person>, List<Person>> biFunction) {
return biFunction.apply(age, personList);
}
}
真諦:函數式接口,傳遞的是行為,而不是數據。
Predicate 類詳解(謂詞)
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);
}
}
默認調用:boolean test(T t)
給定一個輸入參數,判斷是否滿足條件。滿足則返回true,不滿足返回false。
測試案例:
package com.dawa.jdk8;
import java.util.function.Predicate;
public class PreDicateTest {
public static void main(String[] args) {
Predicate<String> predicate = p -> p.length() > 5;
System.out.println(predicate.test("hello"));
}
}
這個接口會在流stream
里面得到大量的運用。上述案例在 stream的 filter()
方法參數中使用。
到現在為止,Function包下的接口已經基礎了兩個了。
可是只是講了幾個特別重要的接口,其他的接口是沒時間一個一個講的。
這個時候我去看了一下源碼,發現JAVA8底層源碼,大量的使用函數接口來進行實現。
道阻且長。~ 加油。
2019年12月29日22:18:25。明天就要上班了,今晚早點休息。