《Java8函數語言程式設計》讀書筆記---常用的流操作

J_W發表於2018-12-11

引用值,而不是變數

內部匿名類中,只能使用該方法final型別的變數。但是這一限制在java中不強制,但既成事實上這個變數應該是final的。

但是在java的函式式表示式中,要求變數必須是effectively final。換句話說lambda表示式引用的是值,而不是變數。

 List<Integer> list= Arrays.asList(1,2,4,6,3);
        //old way
        int count=0;
        for (Integer i:
        list){
            if(i<5)
                count++;
        }
        System.out.println(count);

        //lambda way
        long count1=  list.stream()
                        .filter(i -> i<5 )
                        .count();
        System.out.println(count1);
複製程式碼

lambda表示式看似更復雜了,對集合做了兩次迭代。其實並不是。filter只描述stream,最終不產生新集合,叫做惰性求職方法;而count這樣的會從stream產生值的方法叫做及早求值方法。

//惰性求值,在filter中不會列印
        list.stream().filter(i -> {
            System.out.println(i);
            return i<5;
        });

        //及早求值,filter中的列印會輸出來
        list.stream().filter(i->{
            System.out.println("j"+i);
            return i<5;
        }).count();
複製程式碼

所以理想方式是一系列惰性求值之後,最後用一個及早求值操作。整個過程和建造者模式有共通之處,建造者模式使用一系列造作設定屬性和配置,最後build方法真正的建立物件。

常用的流操作


        //collect 及早求值,
        List collected = Stream.of("a","b","c")
                               .collect(Collectors.toList());
        assertEquals(asList("a","b","c"), collected);

        //map 轉換成新的流 遍歷一遍,map接受一個function介面;
        List collectedMap = Stream.of("a","b","c")
                                  .map(string->string.toUpperCase())
                                  .collect(Collectors.toList());
        assertEquals(asList("A","B","C"), collectedMap);

        //filter模式,filter接受一個predicate介面,返回ture的留下,false的從流中刪除
        //filter和map的區別是:map:函式介面的返回值替換原值、filter:函式介面的返回值為true則保留原值,false則刪除
        List collectedFilter = Stream.of("a","1b","c")
                .filter(string->string.startsWith("1"))
                .collect(Collectors.toList());
        assertEquals(asList("1b"), collectedFilter);

        //flatMap
        List collectedFlatMap = Stream.of(asList(1,2),asList(3,4))
                .flatMap(numbers -> {
                    System.out.println(numbers);
                    return numbers.stream();
                })
                .collect(Collectors.toList());
        assertEquals(asList(1,2,3,4), collectedFlatMap);

        //max min
        //傳入Comparator介面,返回option物件,get()方法可以獲得String物件;
        String collectedMax = Stream.of("a","1b","c")
                .max(Comparator.comparing(string->string.length())).get();
        assertEquals("1b", collectedMax);

        //reduce模式
        // max min count ... 遍歷stream,累加至accumulator。
        int count= Stream.of(1,2,3)
                .reduce(0,(acc,element)->acc+element);
        assertEquals(6,count);

        //forEach()也是一個及早求值
        List list=new ArrayList();
        Stream.of(1,2,3).forEach(j ->list.add(j));
        System.out.println(list);
複製程式碼

:: 用法(方法引用)

方法引用時lambda表示式的一種簡單形式,標準語法:Classname::methodName
例子:
artist->artist.getName()
Artist::getName

(name,nationality)->new Artist(name,nationality)
 Artist::new
複製程式碼
        //old way
        System.out.println(
                "abEEEcd".chars()
                        .filter(c -> Character.isLowerCase(c))
                        .count()
        );
        //使用::之後更簡單
        System.out.println(
                "abEEEcd".chars()
                .filter(Character::isLowerCase)
                .count()
        );
複製程式碼

流除錯

因為流採用的惰性求值,所以在中間操作時候無法列印中間結果,需要Peek()方法除錯。可以在peek方法中列印或者增加斷點。示例程式碼:
``` java
class Person {
String id;
String name;

public Person(String id, String name) {
    this.id = id;
    this.name = name;
}
複製程式碼

} public class PeekStream {

public static void main(String[] args) {
    Person p1=new Person("1","jiao1");
    Person p2=new Person("2","jiao2");
    Person p3=new Person("3","3jiao");
    List<Person> list=new ArrayList();
    list.add(p1);
    list.add(p2);
    list.add(p3);
    long c=list.stream()
            .peek(p->
                    System.out.println(p.name))
            .filter(p->p.name.startsWith("j")).peek(
                    p-> System.out.println(p.id))
            .map(p->p.id).count();
    System.out.println();
    System.out.println(c);
}
複製程式碼

} ```

相關文章