Java8新特性之三:Stream API
- 什么是Stream
- Stream操作三个步骤
- 筛选与切片
- Stream中间操作--映射
- 排序
什么是Stream
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作,在新版的JPA中,也已经加入了Stream
流(Stream): 是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列.
集合讲的是数据,流讲的是计算
注意:
- Stream 自己不会存储元素
- Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream
- Stream 操作是延迟执行的,这意味着他们会等到需要要结果的时候才执行
Stream操作三个步骤
Stream有如下三个操作步骤:
一、创建Stream
从一个数据源,如集合、数组中获取流。
二、中间操作
一个操作的中间链,对数据源的数据进行操作。
三、终止操作
一个终止操作,执行中间操作链,并产生结果。
要注意的是,对流的操作完成后需要进行关闭操作(或者用JAVA7的try-with-resources)。
第一步创建流
- 可以通过Collection系列集合提供的stream()或者parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
- 通过Arrays中的静态方法stream()获取数组流
Employee[] employees = new Employee[10];
Stream<Employee> stream1 = Arrays.stream(employees);
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x +2 );
@Test
public void test1(){
//1可以通过Collection系列集合提供的stream()或者parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//2.通过Arrays中的静态方法stream()获取数组流
Person[] people = new Person[10];
Stream<Person> stream1 = Arrays.stream(people);
//3.通过Stream 类中的静态方法of()
Stream<String> stringStream = Stream.of("11", "bb", "cc");
//4创建无限流
//迭代
Stream<Integer> integerStream = Stream.iterate(0, (x) -> x + 2);
integerStream.limit(10).forEach(System.out::println);
//生成
Stream.generate(()->Math.random())
.limit(5).forEach(System.out::println);
}
中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理称为“惰性求值”
筛选与切片
filter:接收Lambda,从流中排除某些操作;
limit:截断流,使其元素不超过给定对象
skip(n):跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
distinct:筛选,通过流所生素。需要重新hashcode()和equals()方法;
@Test
public void test2(){
Stream<Person> personStream = personLists.stream().filter((e) -> {
System.out.println("========"+e.getName());
return e.getAge() > 35;
});
personStream.forEach(System.out::println);
System.out.println("++++++++++");
personLists.stream().limit(2).forEach(System.out::println);
System.out.println("++++++++++");
personLists.stream().skip(2).forEach(System.out::println);
System.out.println("++++++++++");
personLists.stream().distinct().forEach(System.out::println);
}
Stream中间操作–映射
- map–接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap–接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
@Test
public void test3(){
Stream.of("aaa","bbb","ccc")
.map((x)->x.toUpperCase())
.forEach(System.out::println);
personLists.stream()
.map(Person::getName)
.forEach(System.out::println);
}
排序
sorted():自然排序
sorted(Comparator com):定制排序
@Test
public void test4(){
// 自然排序
List<String> list = Arrays.asList( "bbb", "ccc" ,"aaa", "ddd");
list.stream().sorted().forEach(System.out::println);
//定制排序
// 定制排序
personLists.stream().sorted((person1,person2)->{
if(person1.getAge()==person2.getAge()){
return 0;
}else {
return person1.getAge()-person2.getAge();
}
}).forEach(System.out::println);
}
终止操作
执行下列操作后,Stream流就会进行终止执行
查找与匹配
allMatch:检查是否匹配所有元素
anyMatch:检查是否至少匹配一个元素
noneMatch:检查是否一个都没匹配
findFirst:返回第一个元素
findAny:返回当前流中任意一个元素
count:返回流中元素的个数
max:返回当前流中最大值
min:返回当前流中最小值
forEach:内部迭代
@Test
public void test5(){
boolean b=personLists.stream().allMatch((person)->{
return person.getAge()>40;
});
System.out.println(b);
boolean b2=personLists.stream().anyMatch((person)->{
return person.getAge()>40;
});
System.out.println(b2);
boolean b3=personLists.stream().noneMatch((person)->{
return person.getAge()>40;
});
System.out.println(b3);
System.out.println(personLists.stream().findFirst());
System.out.println(personLists.stream().findAny());
System.out.println(personLists.stream().count());
System.out.println(personLists.stream().max((person1, persion2) -> {
return person1.getAge() - persion2.getAge();
}));
}
规约
格式:reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
可以将流中元素反复结合,得到一个新值
这个reduce,其实有点类似于Hadoop中的mapReduce,先做map操作,然后做reduce操作
@Test
public void test6(){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer integer =list.stream().reduce( 10,(x,y)->{
return x+y;
});
System.out.println(integer); //65
Optional<Float> salOptional = personLists.stream().map(Person::getSalary).reduce(Float::sum);
System.out.println(salOptional.get()); //2553.0
}
收集
Collection将流转换成其它形式,接收一个Collector接口实现,用于给Stream中元素做汇总的方法
格式:collect(Collector c)
Collector接口实现方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常用收集器实例
@Test
public void test7(){
// 收集放入list中
List<String> list = personLists.stream().map(Person::getName).collect(Collectors.toList());
list.forEach(System.out::println);
Set<String> strings= personLists.stream().map(Person::getName).collect(Collectors.toSet());
System.out.println(strings);
HashSet<String> hashSet = personLists.stream().map(Person::getName).collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
}
@Test
public void test8(){
//总数
Long ages = personLists.stream().collect(Collectors.counting());
System.out.println(ages);
//平均数
Double floatsal = personLists.stream().collect(Collectors.averagingDouble(Person::getSalary));
System.out.println(floatsal);
//合计
Double sumsal = personLists.stream().collect(Collectors.summingDouble(Person::getSalary));
//最大值
Optional<Person> max = personLists.stream().collect(Collectors.maxBy((p1,p2)->Float.compare(p1.getSalary(),p2.getSalary())));
System.out.println(max.get());
//最小值
Optional<Person> min = personLists.stream().collect(Collectors.minBy((p1,p2)->Float.compare(p1.getSalary(),p2.getSalary())));
System.out.println(min.get());
}
@Test
public void test9(){
Map<Integer, List<Person>> listMap = personLists.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(listMap);
}
@Test
public void test10(){
Map<String, Map<String, List<Person>>> stringMapMap = personLists.stream()
.collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy((p) -> {
if (p.getAge() <= 35) {
return "青年";
} else if (p.getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(stringMapMap);
}
@Test
public void test11(){
DoubleSummaryStatistics summaryStatistics = personLists.stream().collect(Collectors.summarizingDouble(Person::getSalary));
System.out.println(summaryStatistics.getAverage());
System.out.println(summaryStatistics.getMax());
}
//分区
@Test
public void test12(){
Map<Boolean, List<Person>> booleanListMap = personLists.stream().collect(Collectors.partitioningBy((p) ->
p.getSalary() > 300f
));
System.out.println(booleanListMap);
}
//连接
@Test
public void test13(){
String collect = personLists.stream().map(Person::getName).collect(Collectors.joining(",", "@@@", "==="));
System.out.println(collect);
}