JDK8特性深刻學習筆記-函數式接口(2)

java8的大多數函數式接口都在java.util.function包下。java

Consumer接口

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

Function的定義

Function函數會獲得一個參數,並返回一個結果,函數的方法是 void apply();

高階函數

若是一個函數,接收一個函數做爲參數,或者返回一個函數做爲返回值,那麼這個函數就叫作高階函數。app

apply

R apply(T t);

apply的語義爲:將函數應用到給定的參數上,T爲函數的輸入類型,R爲函數的返回類型函數

public int compute(int a, Function<Integer, Integer> function){
    return function.apply(a);
}

public String convert(int a, Function<Integer, Integer> function){
    return function.apply(a);
}

compute(1, value -> 2 * value);
convert(5, value -> String.valueOf(value + helloworld));

Function<Integer, Integer> function = value -> value * value;
compute(5,function);

Function不須要在設計時考慮到全部的行爲,在使用的時候,用戶能夠按照本身的思考來傳遞行爲,在調用前根本就不須要知道行爲是什麼。ui

compose

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

compose組合函數首先對輸入應用beforeFunction,而後再應用當前函數。是實際上造成了兩個function的串聯。this

andThen

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

andThencompose正好相反,是先對輸入應用this.apply,而後再應用參數的afterFunction。設計

Function中的andThencompose實際上是爲了實現一種業務場景:須要屢次調用某幾個Function,而Function.apply直接將結果返回,andThencompose返回的依舊是Function。code

BiFunction

BiFunction其實就是Function的一種強化版,能夠同時接受兩個參數進行操做,並返回一個結果。對象

R apply(T t, U u);

接受 T 和 U ,返回 R繼承

經過BiFunction完成兩數相加

public compute(int a, int b, BiFunction<Integer, Integer, Integer> biFuncion){
    return biFunction.apply(a, b);
}

test.compute(1, 2, (value1, value2) -> value1 + value2);

BiFunction的andThen

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的andThen方法,參數是Function而不是BiFunction。這是因爲:andThen的語義爲先執行this.apply,即BiFunction的apply,因爲BiFunction的apply返回結果只有一個值R,而這個值又是做爲參數傳入給after,因爲BiFunction須要接受兩個參數,因此after必須是隻須要接受一個參數的Function。
這也是BiFunction沒有compose方法的主要緣由,由於不管BiFunction仍是Function,返回的結果只有一個,因此沒法應用到當前的BiFunction上。接口

BiFunction 使用場景

public class Person{
    private String userName;

    private int age;
}


public class Test{
    public static void main(String[] args){
        Person p1 = new Person("a", 10);
        Person p2 = new Person("b", 20);
        Person p3 = new Person("c", 30);

        List<Person> list = Arrays.asList(p1, p2, p3);

        Test test = new Test();

//      List<Person> res1 = test.getPersonsByUserName("a", list);
//      List<Person> res2 = test.getPersonsByAge("a", list);
        List<Person> res3 = test.getPersonsByAge2(20, list, (age, personList) -> {
            return personList.stream().filter(person -> person.getAge() >= age).collect(Collectors.toList());
        });

         List<Person> res4 = test.getPersonsByAge2(20, list, (age, personList) -> {
            return personList.stream().filter(person -> person.getAge() < age).collect(Collectors.toList());
        });


        
    }
    // 方式一,經過流的filter
    public List<Person> getPersonsByUserName(String userName, List<Person> persons){
        return persons.stream().filter(person -> person.getUserName().equals(userName)).collect(Collectors.toList());
    }
    // 方式二,經過BiFunctionb包裝
    public List<Person> getPersonsByAge(int age, List<Person> persons){
        BiFunction<Integer, List<Person>, List<Person>> biFunction = (a ,l) -> {
            return l.stream().filter(person -> person.getAge() >= a).collect(Collectors.toList());
        };

        return biFunction.apply(age, persons);
    }

    // 方式三,經過接收BiFunction
    public List<Person> getPersonsByAge2(int age, List<Person> persons, 
                    BiFunction<Integer, List<Person>, List<Person>> biFunction){
        return biFunction.apply(age, persons);
    }
}

若是經過方法三來實現,將方法的實現反轉給調用者,調用者能夠更靈活的規範他想要篩選數據的方式和條件。

Predicate

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
      
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

predicate接受一個參數,並返回一個boolean。

Predicate<String> predicate = p -> p.length() > 5;
predicate.test("aaaaaa");

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

conditionFilter(list, p -> p % 2 ==0);

public void conditionFilter(List<Integer> list, Predicate<Integer> predicate){
    list.forEach(i -> {
        if(predicate.test(i)){
            System.out.println(i);
        }
    })
}

// isEqual 方法使用
System.out.println(Predicate.isEqual("test").test("test"));

Supplier

表示一個結果的供應者,並無要求提供與之前不一樣的結果。不接受任何參數,並返回一個結果。
public interface Supplier<T>{
    T get();
}

在開發時supplier能夠用於工廠,不接受參數並返回實例。

public class Student {
    private String name;

    private Intger age;
}

public class StudentTest{

    // 經過supplier調用 student的構造方法
    Supplier<Student> supplier = () -> new Student();
    supplier.get().getName();

    Supplier<Student> supplier2 = Student::new;
    supplier2.get().getName();
}

對於Supplier來講,須要不接受參數,而且返回結果。因此若是對象中沒有無參構造方法,編譯器則會報錯。

BinaryOperator

@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;
    }
}

BinaryOperator繼承了BiFunction。可是BinaryOperator是一種特殊的BiFunction,它的三個類型都一致

minBy 與 maxBy

minBy接受了一個Comparator函數式接口,返回一個BinaryOperator類型對象,是兩個入參中更小的那個,判斷的標準來自於Comparator比較規則。maxBy則相反。

public class Test {

    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test.cul("avv", "bbbbb", Comparator.comparingInt(String::length)));
        System.out.println(test.cul("avv", "bbbbb", (a, b) -> a.charAt(0) - b.charAt(0)));
        System.out.println(test.cul("avv", "bbbbb", Comparator.comparingInt(a -> a.charAt(0))));
    }

    public String cul(String a, String b , Comparator<String> comparator){
        return BinaryOperator.minBy(comparator).apply(a,b);
    }
}

小結

函數式接口是JDK8中的Stream和Optional等內容的基礎。以上這幾個是其餘函數式接口的基礎。

相關文章
相關標籤/搜索