Java函數式編程整理

Java函數式編程的第一個做用是能夠將匿名類改寫成函數式表達式,由系統自動判斷類型編程

咱們先定義一個接口app

public interface Goods {
    boolean test(int i);
}

傳統的匿名類寫法ide

public class Anonymous {
    public static void main(String[] args) {
        List<Goods> goodsList = new ArrayList<>();
        goodsList.add(new Goods(){
            @Override
            public boolean test(int i) {
                return 5 - i > 0;
            }
        });
        System.out.println(goodsList.get(0).test(3));
    }
}

運行結果:函數式編程

true函數

使用lamdba表示式的寫法工具

public class AnonymousLambda {
    public static void main(String[] args) {
        List<Goods> goodsList = new ArrayList<>();
        goodsList.add(i -> 5 - i > 0);
        System.out.println(goodsList.get(0).test(3));
    }
}

運行結果ui

truethis

像這種一個接口裏面只有一個方法的接口,咱們能夠稱之爲函數接口,JDK中有不少這樣的接口,固然咱們能夠在該接口上打上@FunctionalInterface以代表該接口是一個函數接口spa

@FunctionalInterface
public interface Goods {
    boolean test(int i);
}

咱們先來看一下JDK中的Predicate接口,這是一個能夠進行條件判斷的接口code

咱們先用傳統方式來看一下這麼幾個條件

  • 判斷傳入的字符串的長度是否大於5
  • 判斷傳入的參數是不是偶數
  • 判斷數字是否大於10
public class PredicateOne {
    /**
     * 判斷長度大於5
     * @param judgeString
     * @return
     */
    public boolean judgeStringLength(String judgeString) {
        return judgeString.length() > 5;
    }

    /**
     * 判斷是不是偶數
     * @param judgeInteger
     * @return
     */
    public boolean judgeIntegerOdds(int judgeInteger) {
        return (judgeInteger & 1) == 0;
    }

    /**
     * 判斷數字是否大於10
     * @param num
     * @return
     */
    public boolean judgeSecialNumber(int num) {
        return num > 10;
    }

    public static void main(String[] args) {
        PredicateOne predicateOne = new PredicateOne();
        System.out.println(predicateOne.judgeStringLength("12345"));
        System.out.println(predicateOne.judgeIntegerOdds(12345));
        System.out.println(predicateOne.judgeSecialNumber(12345));
    }
}

運行結果

false
false
true

如今改爲函數式編程以下

public class PredicateTwo<T> {
    public boolean judgeConditionByFunction(T t, Predicate<T> predicate) {
        return predicate.test(t);
    }

    public static void main(String[] args) {
        PredicateTwo<Integer> integerPredicateTwo = new PredicateTwo<>();
        System.out.println(integerPredicateTwo.judgeConditionByFunction(12345,t -> String.valueOf(t).length() > 5));
        System.out.println(integerPredicateTwo.judgeConditionByFunction(12345,t -> (t & 1) == 0));
        System.out.println(integerPredicateTwo.judgeConditionByFunction(12345,t -> t > 10));
    }

運行結果

false
false
true

咱們知道邏輯判斷中有與、或、非的比較,Predicate接口一樣具備這樣的功能,咱們來看一下它的源碼

@FunctionalInterface
public interface Predicate<T> {

    /**
     * 須要實現的比較方法
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

    /**
     * 邏輯與,相似於&&
     *
     * @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);
    }

    /**
     * 邏輯非,相似於!
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * 邏輯或,相似於||
     *
     * @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);
    }

    /**
     * 邏輯等,相似於equals()方法
     *
     * @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);
    }
}

如今咱們加上條件的交集判斷

public class PredicateThree<T> {
    /**
     * 兩個條件的與操做
     * @param t
     * @param predicate
     * @param predicate1
     * @return
     */
    public boolean judgeConditionByFunctionAnd(T t, Predicate<T> predicate,Predicate<T> predicate1) {
        return predicate.and(predicate1).test(t);
    }

    /**
     * 兩個條件的或操做
     * @param t
     * @param predicate
     * @param predicate1
     * @return
     */
    public boolean judgeConditionByFunctionOr(T t, Predicate<T> predicate,Predicate<T> predicate1) {
        return predicate.or(predicate1).test(t);
    }

    /**
     * 對一個條件進行取反
     * @param t
     * @param predicate
     * @return
     */
    public boolean judgeConditionByFunctionNegate(T t,Predicate<T> predicate) {
        return predicate.negate().test(t);
    }

    /**
     * 判斷兩個對象的值是否相等
     * @param t1
     * @param t2
     * @return
     */
    public boolean judgeConditionIsEquals(T t1,T t2) {
        return Predicate.isEqual(t1).test(t2);
    }

    public static void main(String[] args) {
        PredicateThree<Integer> integerPredicateThree = new PredicateThree<>();
        System.out.println(integerPredicateThree.judgeConditionByFunctionAnd(12345,t -> t > 10,t ->(t & 1) == 0));
        System.out.println(integerPredicateThree.judgeConditionByFunctionOr(12345,t -> t > 10,t ->(t & 1) == 0));
        System.out.println(integerPredicateThree.judgeConditionByFunctionNegate(12345,t -> t > 10));
        System.out.println(integerPredicateThree.judgeConditionIsEquals(123,123));
    }
}

運行結果

false
true
false
true

咱們再來看一下JDK中的Consumer接口,Consumer的做用是 給定義一個參數,對其進行(消費)處理,處理的方式能夠是任意操做.

咱們來獲取一羣人中名字爲lisa的全部人,傳統方式以下

@Data
@AllArgsConstructor
public class Person {
    private String name;
    private int age;
}
public class ConsumerOne {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        Consumer<Person> consumer = new Consumer<Person>() {
            @Override
            public void accept(Person person) {
                if (person.getName().equals("lisa")) {
                    personList.add(person);
                }
            }
        };
        List<Person> list = Arrays.asList(
                new Person("lisa", 23),
                new Person("Mike", 33),
                new Person("lisa", 27),
                new Person("Jack", 25)
        );
        for (Person person : list) {
            consumer.accept(person);
        }
        System.out.println(JSON.toJSONString(personList));
    }

}

運行結果

[{"age":23,"name":"lisa"},{"age":27,"name":"lisa"}]

改寫成函數式編程以下

public class ConsumerTwo {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        Consumer<Person> consumer = t -> {
            if (t.getName().equals("lisa")) {
                personList.add(t);
            }
        };
        Arrays.asList(
                new Person("lisa", 23),
                new Person("Mike", 33),
                new Person("lisa", 27),
                new Person("Jack", 25)
        ).stream().forEach(consumer);
        System.out.println(JSON.toJSONString(personList));
    }
}

運行結果

[{"age":23,"name":"lisa"},{"age":27,"name":"lisa"}]

stream後面會全面講解,咱們來看一下Consumer接口的源碼

@FunctionalInterface
public interface Consumer<T> {

    /**
     * 給指定的參數t執行定義的操做
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     *  對給定的參數t執行定義的操做執行再繼續執行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); };
    }
}

如今咱們只須要大於25歲的lisa

public class ConsumerThree {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        Consumer<Person> consumer = t -> {
            if (t.getName().equals("lisa")) {
                personList.add(t);
            }
        };
        consumer = consumer.andThen(t -> personList.removeIf(x -> x.getAge() < 25));
        Arrays.asList(
                new Person("lisa", 23),
                new Person("Mike", 33),
                new Person("lisa", 27),
                new Person("Jack", 25)
        ).stream().forEach(consumer);
        System.out.println(JSON.toJSONString(personList));
    }
}

運行結果

[{"age":27,"name":"lisa"}]

這裏removeIf()的參數是一個Predicate接口,它的源碼以下,它是在Collection接口源碼中

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
        if (filter.test(each.next())) {
            each.remove();
            removed = true;
        }
    }
    return removed;
}

咱們再來看一下JDK中的Function接口,Function的做用是將一個給定的對象進行加工,而後返回加工後的對象,這個加工能夠是任何操做.

傳統方式以下

@Data
@AllArgsConstructor
@ToString
public class Person {
    private String name;
    private int age;
}
@AllArgsConstructor
@Data
@ToString
public class Result {
    private String msg;
    private String code;
    private Person person;
}
public class FunctionOne {
    public static void main(String[] args) {
        Function<Person,Result> function = new Function<Person, Result>() {
            @Override
            public Result apply(Person person) {
                return new Result("成功","200",person);
            }
        };
        System.out.println(function.apply(new Person("lisa",24)));
    }
}

運行結果

Result(msg=成功, code=200, person=Person(name=lisa, age=24))

改寫成函數式編程以下

public class FunctionTwo {
    public static void main(String[] args) {
        Function<Person,Result> function = x -> new Result("成功","200",x);
        System.out.println(function.apply(new Person("lisa",24)));
    }
}

運行結果

Result(msg=成功, code=200, person=Person(name=lisa, age=24))

Function接口的源碼以下

@FunctionalInterface
public interface Function<T, R> {

    /**
     *  將一個給定的對象進行加工,而後返回加工後的對象,能夠將該方法理解爲一個一維函數,參數R是自變量,參數T是因變量. 
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

    /**
     *  組合函數,在調用當前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));
    }

    /**
     *  組合函數,在調用當前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));
    }

    /**
     *  原函數,返回與參數一致的函數,便可以理解爲 y = x 
     *
     * @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;
    }
}

----------------------------------------------------------------------------------

而另外一個最主要的做用就是對集合的操做,從傳統編程到函數式編程(lambda),咱們先來看一個最簡單的例子

@Data
@AllArgsConstructor
public class Artist {
    private String name;
    private String homeTown;

    public boolean isFrom(String homeTown) {
        if (this.homeTown.equals(homeTown)) {
            return true;
        }
        return false;
    }
}

這是一個藝術家的簡單類,包含名字和家鄉。

如今咱們來建立一個藝術家的集合,而後斷定來自倫敦的藝術家有多少人

public class ComeFrom {
    public static void main(String[] args) {
        List<Artist> artists = new ArrayList<>();
        artists.add(new Artist("Martin","London"));
        artists.add(new Artist("Shirly","Beijing"));
        artists.add(new Artist("Dilon","London"));
        artists.add(new Artist("Dave","NewYork"));
        int count = 0;
        for (Artist artist : artists) {
            if (artist.isFrom("London")) {
                count++;
            }
        }
        System.out.println(count);
    }
}

運行結果:

2

如今咱們來改形成函數式的編程

public class ComeFromStream {
    public static void main(String[] args) {
        List<Artist> artists = new ArrayList<>();
        artists.add(new Artist("Martin","London"));
        artists.add(new Artist("Shirly","Beijing"));
        artists.add(new Artist("Dilon","London"));
        artists.add(new Artist("Dave","NewYork"));
        long count = artists.stream().filter(artist -> artist.isFrom("London"))
                .count();
        System.out.println(count);
    }
}

運行結果

2

這裏第一種方式,咱們稱爲外部迭代;而第二種方式,咱們稱爲內部迭代,而stream是這種用函數式編程方式在集合類上進行復雜操做的工具。

若是咱們對代碼稍做修改

public class ComeFromStream {
    public static void main(String[] args) {
        List<Artist> artists = new ArrayList<>();
        artists.add(new Artist("Martin","London"));
        artists.add(new Artist("Shirly","Beijing"));
        artists.add(new Artist("Dilon","London"));
        artists.add(new Artist("Dave","NewYork"));
        artists.stream().filter(artist -> {
            System.out.println(artist.getName());
            return artist.isFrom("London");
        });
    }
}

執行該端代碼,沒有任何輸出。像這種只過濾不計數的,filter只刻畫出了Stream,但並無產生新的集合的方法,咱們稱之爲惰性求值方法;而像count這樣最終會從Stream產生值的方法叫作及早求值方法。

咱們再把上述代碼改回求值。

public class ComeFromStream {
    public static void main(String[] args) {
        List<Artist> artists = new ArrayList<>();
        artists.add(new Artist("Martin","London"));
        artists.add(new Artist("Shirly","Beijing"));
        artists.add(new Artist("Dilon","London"));
        artists.add(new Artist("Dave","NewYork"));
        long count = artists.stream().filter(artist -> {
            System.out.println(artist.getName());
            return artist.isFrom("London");
        }).count();
        System.out.println(count);
    }
}

運行結果

Martin
Shirly
Dilon
Dave
2

判斷一個操做是惰性求值仍是及早求值很簡單:只需看它的返回值。若是返回值是Stream,那麼是惰性求值;若是返回值是另外一個值或爲空,那麼就是及早求值。整個過程和建造者模式有共通之處。建造者模式使用一系列操做設置屬性和配置,最後調用build方法,這時,對象才被真正建立。

相關文章
相關標籤/搜索