讀書筆記——《Java 8實戰》系列之Lambda表達式(二)

轉自 http://www.wxueyuan.com/blog/articles/2017/10/16/1508115706213.html

上一篇博客中,我們介紹了Lambda表達式的基本概念以及語法。在本片博客中,我們將繼續和大家分享一些關於Lambda表達式的知識。

函數式接口只定義了一個抽象方法,該抽象方法的簽名也被稱爲函數描述符。爲了應用不同的Lambda表達式,Java 的庫設計師們提供了一些常用的函數式接口,比如我們之前接觸到的Comparable,Runnable和Callable。Java 8在此基礎上,又增加了幾個新的函數接口,接下來我們就一起來了解它們一下。

java.util.function.Predicate

Predicate接口定義了一個名叫test的抽象方法,他接受泛型T的對象,並返回一個Boolean值。看過本系列讀書筆記的同學們是不是覺得很眼熟?沒錯,它和我們在行爲參數化博客中自己創建的函數式接口一模一樣。當我們需要使用一個傳入對象並返回布爾值的表達式時,直接使用它吧。

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

    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> results = new ArrayList<>();
        for(T s: list){
            if(p.test(s)){
                results.add(s);
            }
        }
        return results;
    }
    Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();

    List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

java.util.function.Consumer

Consumer定義了一個accept抽象方法。它接受泛型類型對象T,並沒有返回任何值。如果我們需要訪問T類型的對象,並對其執行某些操作,我們就可以使用這個接口了

    @FunctionalInterface
    public interface Consumer<T>{
        void accept(T t);
    }

    public static <T> void forEach(List<T> list, Consumer<T> c){
        for(T t:list){
            c.accept(t);
        }
    }

    forEach(Arrays.asList(1,2,3,4,5), (Integer i)-> System.out.println(i));

java.util.function.Function

    @FunctionalInterface
    public interface Function<T,R>{
        R apply(T t);
    }

    public static <T,R> List<R> map(List<T> list, Function<T,R> f){
        List<R> result = new ArrayList<R>();
        for(T t: list){
            result.add(f.apply(t));
        }
    }

    List<Integer> list = map(Arrays.asList("hello","world","Jesmin"),(String s) -> s.length());

接下來我們來一起總結一些常用的Lambda的例子以及可以使用的函數式接口。

使用案例Lambda示例對應的函數式接口
布爾表達式(List<String> list) -> list.isEmpty()Predicate<List<String>>
創建對象( ) -> new String()Supplier<String>
消費一個對象( String s ) -> { System.out.println(s);}Consumer<String>
從某個對象中抽取屬性( Student s ) -> s.getHeight()Function<Student,Integer>或ToIntFunction<Student>
組合兩個值( int a, int b ) -> a*b IntBinaryOperator
比較兩個對象( Student s1, Student s2 ) -> s1.getHeight().compareTo(s2.getHeight())Comparator<Student>

迄今爲止,我們所介紹的所有Lambda表達式都只用到了其主體中的參數,如使用了學生實例的身高屬性

    List<Student> result = filter(students, (Student s) -> s.getHeight()>=180));

但實際上Lambda表達式也允許我們使用自由變量(不允許當作參數,可以在主體中使用外層作用域中定義的變量),如:

    int num = 5;
    Runnable r = () -> System.out.println(num);

Lambda表達式同樣能夠在主體中使用實例變量和靜態變量。但是局部變量必須顯式聲明爲final或事實上爲final,換句話說,Lambda表達式主體中使用過的局部變量,不能被再次賦值。

錯誤示範:

    int num = 5;
    Runnable r = () -> System.out.println(num);
    //此處編譯會報錯,因爲被Lambda表達式主體引用的局部變量num被再次賦值了
    num = 3;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章