Lambda
基本语法
- 流只能遍历一次
我们可以把流想象成一条流水线,流水线的源头是我们的数据源(一个集合),数据源中的元素依次被输送到流水线上,我们可以在流水线上对元素进行各种操作。一旦元素走到了流水线的另一头,那么这些元素就被“消费掉了”,我们无法再对这个流进行操作。当然,我们可以从数据源那里再获得一个新的流重新遍历一遍。
- stream是采用内部迭代方式
若要对集合进行处理,则需我们手写处理代码,这就叫做外部迭代。而要对流进行处理,我们只需告诉流我们需要什么结果,处理过程由流自行完成,这就称为内部迭代!
获取流
//集合方式
List<Person> list = new ArrayList<Person>();
Stream<Person> stream = list.stream();
//数组方式
String[] names = {"chaimm","peter","john"};
Stream<String> stream = Arrays.stream(names);
Stream<String> stream = Stream.of("chaimm","peter","john");
筛选filter
List<Person> result = list.stream()
.filter(Person::isStudent)//筛选出所有的学生
.collect(toList());
去重
List<Person> result = list.stream()
.distinct()//普通变量容易去重 对象是地址唯一标识
.collect(toList());
截取
List<Person> result = list.stream()
.limit(3)//截取前3个元素
.collect(toList());
跳过
List<Person> result = list.stream()
.skip(3)//跳过前3个元素
.collect(toList());
映射
对流中的每个元素执行一个函数,使得元素转换成另一种类型输出。流会将每一个元素输送给map函数,并执行map中的Lambda表达式,最后将执行结果存入一个新的流中
List<String> result = list.stream()
.map(Person::getName)//取出姓名 并作为一个集合
.collect(toList())
合并多个流
-
众多小流
List<String> list = new ArrayList<String>(); list.add("I am a boy"); list.add("I love the girl"); list.add("But the girl loves another girl"); List<Stream<String>> collect = list.stream() .map(line -> line.split(" "))//每个字符串变成一个数组 .map(Arrays::stream)//将每个String[]变成一个流 .collect(Collectors.toList());//此时一个大流里面包含很多小流 System.out.println(collect); List<String> collect1 = list.stream() .map(line -> line.split(""))//每个字符串变成一个数组 .flatMap(Arrays::stream)//将小流合并成一个大流 .collect(Collectors.toList()); System.out.println(collect1); //输出结果 [java.util.stream.ReferencePipeline$Head@6193b845, java.util.stream.ReferencePipeline$Head@2e817b38, java.util.stream.ReferencePipeline$Head@c4437c4] ---------------------------------------------------------- [I, am, a, boy, I, love, the, girl, But, the, girl, loves, another, girl]
匹配元素
- anyMatch 是否匹配任一元素
- allMatch 是否匹配所有元素
- noneMatch 是否未匹配所有元素
获取任一元素 findAny && 获取第一个元素findFirst
Optional<Person> person = list.stream() .findAny(); Optional<Person> person = list.stream() .findFirst();
规约
归约是将集合中的所有元素经过指定运算,折叠成一个元素输出,如:求最值、平均数等,这些操作都是将一个集合的元素折叠成一个元素输出
int age = list.stream().reduce(0, (person1,person2)->person1.getAge()+person2.getAge());//对年龄求和
-
使用Integer.sum求和
//如果当前流的元素为数值类型,那么可以使用Integer提供了sum函数代替自定义的Lambda表达式 int age = list.stream().reduce(0, Integer::sum);
-
数值流的使用
StreamAPI提供了三种数值流:IntStream、DoubleStream、LongStream,也提供了将普通流转换成数值流的三种方法:mapToInt、mapToDouble、mapToLong
IntStream stream = list.stream() .mapToInt(Person::getAge);
-
数值流计算 max、min、sum、average
OptionalInt maxAge = list.stream() .mapToInt(Person::getAge) .max(); //mapToInt、mapToDouble、mapToLong进行数值操作后的返回结果分别为:OptionalInt、OptionalDouble、OptionalLong
-
例子
//1.分组计数 List<Student> list1= Arrays.asList(new Student(1,"one","zhao"),new Student(2,"one","qian"),new Student(3,"two","sun")); //1.1根据某个属性分组计数 Map<String,Long> result1=list1.stream().collect(Collectors.groupingBy(Student::getGroupId,Collectors.counting())); System.out.println(result1); //1.2根据整个实体对象分组计数,当其为String时常使用 Map<Student,Long> result2=list1.stream().collect(Collectors.groupingBy(Function.identity(),Collectors.counting())); System.out.println(result2);
对基本数据类型进行分组计数
List<Integer> list = Arrays.asList(1, 2, 3, 2, 4, 1); Map<Integer, Long> longMap = list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); longMap.forEach((key, value) -> { System.out.println(key + "," + value); });
对数据分组
class Demo {
private int code;
private int count;
public Demo(int code, int count) {
this.code = code;
this.count = count;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public static void main(String[] args) {
Foo foo1 = new Foo(1, 2);
Foo foo2 = new Foo(2, 23);
Foo foo3 = new Foo(2, 6);
List<Demo> list = new ArrayList<>(4);
list.add(foo1);
list.add(foo2);
list.add(foo3);
Map<Integer, List<Demo>> collect = list.stream().collect(Collectors.groupingBy(Foo::getCode));
List<Demo> list1 = collect.get(1);
List<Demo> list2 = collect.get(2);
list1.forEach(e -> System.out.println(e.getCode() + ":" + e.getCount()));
System.out.println("-----------这里是分界线-----------------------------");
list2.forEach(e -> System.out.println(e.getCode() + ":" + e.getCount()));
}
对数据分组求和
//接上面 如果仅仅是分组 还需要手动求和的 这样不方便 因此可以这样
Demo demo1 = new Demo(1, 2);
Demo demo2 = new Demo(2, 23);
Demo demo3 = new Demo(2, 6);
List<Demo> list = new ArrayList<>(4);
list.add(foo1);
list.add(foo2);
list.add(foo3);
Map<Integer, IntSummaryStatistics> collect = list.stream().collect(Collectors.groupingBy(Demo::getCode, Collectors.summarizingInt(Demo::getCount)));
IntSummaryStatistics statistics1 = collect.get(1);
IntSummaryStatistics statistics2 = collect.get(2);
System.out.println(statistics1.getSum());//2
System.out.println(statistics1.getAverage());//2.0
System.out.println(statistics1.getMax());//2
System.out.println(statistics1.getMin());//2
System.out.println(statistics1.getCount());//1
System.out.println(statistics2.getSum());//29
System.out.println(statistics2.getAverage());//14.5
System.out.println(statistics2.g
etMax());//26
System.out.println(statistics2.getMin());//3
System.out.println(statistics2.getCount());//2
问题:
List<String> list = new ArrayList<String>();
list.add("I am a boy");
list.add("I love the girl");
list.add("But the girl loves another girl");
List<String> collect1 = list.stream()
.map(line -> line.split(""))//每个字符串变成一个数组
.flatMap(Arrays::stream)//将小流合并成一个大流
.collect(Collectors.toList());
为什么flatMap中要用Arrays::stream而不是List::stream?
因为flatMap上一步map执行的是split操作,返回的数据类型是数组,所以下一行使用Arrays::stream而不是List::stream
不光这里,lambda表达式的其他应用里也可以根据上文的结构动态的选择待调用的方法
lambda表达式中::的几种用法
-
静态方法引用
如
Person::compareByAge
-
构造方法引用
Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);
-
任意对象的实例方法引用
如
String::compareToIgnoreCase
-
特定实例对象的方法引用
class ComparisonProvider{
public int compareByName(Person a, Person b)
{
return a.getName().compareTo(b.getName());
}
public int compareByAge(Person a, Person b)
{
return a.getBirthday().compareTo(b.getBirthday());
}
}
//main方法
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);