引用值,而不是變數
內部匿名類中,只能使用該方法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);
}
複製程式碼
} ```