Java函數式編程隨想

java函數式編程的類主要定義在java.util.function包下。快速瀏覽了下該包下的一些類和接口。讀者要想看懂function相關的源碼,也需要對lambda表達式和泛型有一定的瞭解。本文只講function包下的一些源碼解析

Predicate接口

Predicate在java函數式編程中起到了過濾的作用。java 8函數編程引入了Stream類。該類配合function包下定義的一些接口,實現了一系列的函數式編程方法。 比如Stream類的過濾功能

過濾一些符合條件的數據
Stream<T> filter(Predicate<? super T> predicate);
//函數式編程的註解
@FunctionalInterface
public interface Predicate<T> {

    //判斷t是否符合條件
    //例如判斷一個數是否奇數 return t % 2 != 0
    boolean test(T t);

    //這個是接口的一個默認實現的方法表示兩個Predicate之間是與的關係
    //例如Predicate<Integer> isOdd 表示篩選出奇數
    //Predicate<Integer> biggerThan10 表示篩選出大於10的數
    //Predicate<Integer> and = isOdd.and(biggerThan10)表示大於10的奇數

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
        //上面lambda等價於
        //final Predicate self = this;
        //return new Predicate<T>(){
        //     boolean test(T t){
        //        retun self.test(t) && other.test(t)
        //     }
        //}
    }

    //求反Predicate<T> isEven = isOdd.negate()表示篩選出偶數
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    //或的關係,用and的例子來講 isOdd.or(biggerThan10)表示大於10或者是奇數的數
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

}

下面我們結合一個例子來了解下Predicate的原始用法(結合Stream使用才叫高級用法)

給定一個集合{1,2,3,4,5,6,7,8,9,10}我們要找出其中的奇數。結合Predicate我們可以這樣實現


        Predicate<Integer> p = new Predicate<Integer>(){
            public boolean test(Integer o){
                return o % 2 != 0;
            }
        };
        Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
        for(Integer i:arr){
            if(p.test(i)){
                System.out.print(i);//輸出13579
            }
        }

        用lambda
        Predicate<Integer> p = o->  o % 2 != 0;
        Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
        for(Integer i:arr){
            if(p.test(i)){
                System.out.println(i);
            }
        }

        用Stream
        IntStream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .filter(i -> i % 2 != 0)
            .forEach(i -> System.out.print(i));//輸出13579

Consumer接口

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

andThen等價於

    default Consumer<T> andThen(final Consumer<? super T> after) {
        Objects.requireNonNull(after);
        final Consumer<T> self = this;
        return new Consumer<T>() {
            @Override
            public void accept(T t) {
                self.accept(t) && after.accept(t);
            }
        }
    }

舉個例子

    Consumer<Integer> c1 = new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        };
        Consumer<Integer> c2 = new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer*integer);
            }
        };
        c1.andThen(c2).accept(2);// 結果 2  4

主要用在Stream的forEach中

    void forEach(Consumer<? super T> action);

Function接口

Fuction

@FunctionalInterface
public interface Function<T, R> {

    //從T類型轉換到R類型
    R apply(T t);

    //組合最終返回的是V->R的轉換。首先是V->T 然後T->R的轉換
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    //先轉換T->R然後轉換R->V最終返回的是T->V
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * 返回自己
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

舉例說明 將數字轉換成相應的英文單詞

 Map<Integer, String> map = new HashMap<>();
        map.put(1, "one");
        map.put(2, "two");
        map.put(3, "three");
        map.put(4, "four");
        map.put(5, "five");

        Function<Integer, String> function = new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) {
                return map.get(integer);
            }
        };
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept(function.apply(1));//結果 one

如果要獲取數字對應的英文單詞的字母個數呢

        Function<Integer, String> getLetter = new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) {
                return map.get(integer);
            }
        };
        Function<String, Integer> getLetterLength = new Function<String, Integer>() {
            @Override
            public Integer apply(String letter) {
                return letter.length();
            }
        };
        Consumer<Integer> consumer = new Consumer<Integer>() {
            @Override
            public void accept(Integer s) {
                System.out.println(s);
            }
        };
        consumer.accept(getLetter.andThen(getLetterLength).apply(1));//結果3

lambda表達式

 Consumer<Integer> consumer = System.out::print;
        Function<Integer, String> getLetter = i->map.get(i);
        Function<String, Integer> getLetterLength = s->s.length();
        Function<Integer, Integer> indexAndSize = getLetter.andThen(getLetterLength);

        consumer.accept(indexAndSize.apply(1));

Stream中使用

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

用Stream實現一個簡單的例子

打印從0到10 偶數對應的英文單詞

        Map<Integer, String> map = new HashMap<>();
        map.put(0, "zero");
        map.put(1, "one");
        map.put(2, "two");
        map.put(3, "three");
        map.put(4, "four");
        map.put(5, "five");
        map.put(6, "six");
        map.put(7, "seven");
        map.put(8, "eight");
        map.put(9, "nine");


        Stream<Integer> stream = Stream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        stream.filter(i -> i % 2 == 0)
                .map(i -> map.get(i))
                .forEach(s -> System.out.println(s));

結果                
zero
two
four
six
eight
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章