引用值,而不是变量
内部匿名类中,只能使用该方法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);
}
} ```