Stream是一种可供流式操作的数据视图,有些类似数据库中的视图,不改变源数据集合,如果进行改变的操作会返回新的数据集合。
总的来讲它有三大特性:1、stream不存储数据 ; 2、stream不改变源数据 ; 3、stream的延迟执行特性
Stream API常用方法 | ||
中间操作 (Intermediate operations) | 无状态(Stateless) | unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek() |
有状态(Stateful) | distinct() sorted() limit() skip() | |
结束操作 (Terminal operations) | 非短路操作 | forEach() forEachOrdered() toArray() reduce() collect() max() min() count() |
短路操作 (short-circuiting) | anyMatch() allMatch() noneMatch() findFirst() findAny() |
常用中间件 | 结束操作 |
filter:过滤流,过滤流中的元素,返回一个符合条件的Stream map:转换流,将一种类型的流转换为另外一种流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本类型对应的Stream) flatMap:简单的说,就是一个或多个流合并成一个新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回对应的IntStream、LongStream、DoubleStream流。) peek:主要用来查看流中元素的数据状态。
distinct:返回去重的Stream。 sorted:返回一个排序的Stream。 limit:返回前n个元素数据组成的Stream。属于短路操作 skip:返回第n个元素后面数据组成的Stream。 | forEach: 循环操作Stream中数据。 toArray: 返回流中元素对应的数组对象。 reduce: 聚合操作,用来做统计。 collect: 聚合操作,封装目标数据。 min、max、count: 聚合操作,最小值,最大值,总数量。 forEachOrdered: 暗元素顺序执行循环操作。
anyMatch: 短路操作,有一个符合条件返回true。 allMatch: 所有数据都符合条件返回true。 noneMatch: 所有数据都不符合条件返回true。 findFirst: 短路操作,获取第一个元素。 findAny: 短路操作,获取任一元素。 |
所有操作分为两类:中间操作和结束操作,中间操作只是一种标记,只有结束操作才会触发实际计算
中间操作:(1)无状态中间操作是指元素的处理不受前面元素的影响;(2)有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果。
结束操作:(1)短路操作是指不用处理全部元素就可以返回结果,比如找到第一个满足条件的元素。
之所以要进行如此精细的划分,是因为底层对每一种情况的处理方式不同。
Stream简介
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。
Stream和Collection的区别主要有:
1.stream本身并不存储数据,数据是存储在对应的collection里,或者在需要的时候才生成的;
2.stream不会修改数据源,总是返回新的stream;
3.stream的操作是懒执行(lazy)的:仅当最终的结果需要的时候才会执行
Stream的生成方式
1)从Collection和数组获得
- Collection.stream()
- Collection.parallelStream() (并行执行的流.它通过默认的ForkJoinPool,可能提高多线程任务的速度)
- Arrays.stream(T array) or Stream.of()
(2)从BufferedReader获得
- java.io.BufferedReader.lines()
(3)静态工厂
- java.util.stream.IntStream.range()
- java.nio.file.Files.walk()
(4)自己构建
- java.util.Spliterator
(5)其他
- Random.ints()
- BitSet.stream()
- Pattern.splitAsStream(java.lang.CharSequence)
- JarFile.stream()
案例说明
public class Person { // 举例实体类
private Integer id;
private String name;
private String sex;
private Integer age;
//get,set方法和满参构造函数忽略
}
1、map相关
public class TestMap {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person(1,"张三","男",38));
personList.add(new Person(2,"小小","女",2));
personList.add(new Person(3,"李四","男",65));
personList.add(new Person(4,"王五","女",20));
personList.add(new Person(5,"赵六","男",38));
personList.add(new Person(6,"大大","男",65));
//1、只取出该集合中所有姓名组成一个新集合
List<String> nameList=personList.stream().map(Person::getName).collect(Collectors.toList());
System.out.println(nameList.toString());
//2、只取出该集合中所有id组成一个新集合
List<Integer> idList=personList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList());
System.out.println(idList.toString());
//3、list转map,key值为id,value为Person对象
Map<Integer, Person> personmap = personList.stream().collect(Collectors.toMap(Person::getId, person -> person));
System.out.println(personmap.toString());
//4、list转map,key值为id,value为name
Map<Integer, String> namemap = personList.stream().collect(Collectors.toMap(Person::getId, Person::getName));
System.out.println(namemap.toString());
//5、进行map集合存放,key为age值 value为Person对象 它会把相同age的对象放到一个集合中
Map<Integer, List<Person>> ageMap = personList.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(ageMap.toString());
//6、获取最小年龄
Integer ageMin = personList.stream().mapToInt(Person::getAge).min().getAsInt();
System.out.println("最小年龄为: "+ageMin);
//7、获取最大年龄
Integer ageMax = personList.stream().mapToInt(Person::getAge).max().getAsInt();
System.out.println("最大年龄为: "+ageMax);
//8、集合年龄属性求和
Integer ageAmount = personList.stream().mapToInt(Person::getAge).sum();
System.out.println("年龄总和为: "+ageAmount);
}
}
这里要注意,如果list转map的key不唯一,结果会报错,如果不确定你的key是否唯一,可以做如下修改:
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person(1, "张三", "男", 38));
personList.add(new Person(2, "小小", "女", 2));
personList.add(new Person(3, "李四", "男", 65));
personList.add(new Person(4, "王五", "女", 20));
personList.add(new Person(5, "赵六", "男", 38));
personList.add(new Person(6, "大大", "男", 65));
//list转map,key值为age,value为Person对象
// 1.错误情况
Map<Integer, Person> error = personList.stream().collect(Collectors.toMap(Person::getAge, person -> person));
// 修改情况(以第一次插入的value为主)
Map<Integer, Person> chang1 = personList.stream().collect(Collectors.toMap(Person::getAge, person -> person,
(key1, key2) -> key1));
System.out.println(chang1.toString());
// 修改情况(以最后一次插入的value为主)
Map<Integer, Person> chang2 = personList.stream().collect(Collectors.toMap(Person::getAge, person -> person,
(key1, key2) -> key2));
System.out.println(chang2.toString());
}
2、filter相关
public class TestFilter {
public static void main(String[] args) {
List<Person> persionList = new ArrayList<Person>();
persionList.add(new Person(1, "张三", "男", 8));
persionList.add(new Person(2, "小小", "女", 2));
persionList.add(new Person(3, "李四", "男", 25));
persionList.add(new Person(4, "王五", "女", 8));
persionList.add(new Person(5, "赵六", "女", 25));
persionList.add(new Person(6, "大大", "男", 65));
//1、查找年龄大于20岁的人数
long age=persionList.stream().filter(p->p.getAge()>20).count();
System.out.println(age);
//2、查找年龄大于20岁,性别为男的人数
List<Person> ageList=persionList.stream().filter(p->p.getAge()>20).filter(p->"男".equals(p.getSex())).collect(Collectors.toList());
System.out.println(ageList.size());
}
}