Stream是Java8中处理集合的关键抽象概念,它能够指定你但愿对集合进行的操做,能够执行很是复杂的查找、过滤和映射数据等操做。使用Stream API对集合进行操做,就相似与使用SQL执行的数据库操做。也可使用Stream API来并行执行操做。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。html
是数据渠道,用于操做数据源(集合、数组等)所生成的元素序列 集合讲的是数据,流讲的是计算数据库
PS:数组
下面的图能够比较直观的反映这一过程: dom
Java8中的Collection接口被扩展,提供了两个获取流的方法:ide
- default Stream<T> stream():返回一个顺序流
- default Stream<T> parallelStream():返回一个并行流
示例代码:函数
List<Integer> list = new ArrayList<>(); Stream<Integer> stream1 = list.stream(); Stream<Integer> stream2 = list.parallelStream();
Java8的Arrays的静态方法stream()能够获取数据流测试
- static <T> Stream<T> stream(T[] arrays):返回一个流
示例代码:this
Integer[] integers = new Integer[10]; Stream<Integer> stream = Arrays.stream(integers);
经过Stream类中的静态方法of(),经过显示值建立一个流,能够接收任意数量的参数spa
- public static <T> Stream<T> of(T ... values):返回一个流
示例代码:code
Stream<Integer> stream = Stream.of(1, 2, 3);
使用静态方法Stream.iterate()和Stream.generate(),建立无限流
- 迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
- 生成:public static<T> Stream<T> generate(Supplier<T> s)
示例代码:
// 迭代 Stream stream1 = Stream.iterate(0, (x) -> x + 2); // 生成 Stream stream2 = Stream.generate(() -> Math.random());
多个中间操做能够链接起来造成一个流水线,除非流水线上触发终止操做,不然中间操做不会执行任何的处理!而在终止操做时一次性所有处理,称之为“惰性求值”。
- filter:结合搜lambda,从流中排除元素
- limit:截断流,使其元素不超过给定数量
- skip(n):跳过元素,返回一个删除了前n个元素的流;若流中元素不足n个,则返回一个空流;与limit(n)互补
- distinct:筛选,经过流所生成的元素的hashCode()和equals()去除重复元素
示例代码:
public class TestStreamApi { private static List<Demo> demoList = Arrays.asList( new Demo(1, "哈哈哈"), new Demo(2, "嘿嘿嘿嘿"), new Demo(3, "呵呵呵"), new Demo(4, "恩恩恩恩"), new Demo(5, "哼哼哼"), new Demo(6, "啧啧啧"), new Demo(5, "哼哼哼"), new Demo(8, "哼") ); public static void main(String[] args) { // 中间操做不会执行任何操做 Stream<Demo> demoStream = demoList.stream() .filter((x) -> x.getRemark().length() == 3) .limit(4) .skip(1) .distinct(); // 终止操做一次性执行所有内容 // 内部迭代:迭代操做由Stream API完成 demoStream.forEach(System.out::println); } }
运行结果: 3-呵呵呵 5-哼哼哼 6-啧啧啧
**注意:**distinct筛选经过流所生成的元素的hashCode()和equals()去除重复元素,因此须要重写Demo的hashCode()和equals()方法。
- map:接收Lambda,将元素转换成其它形式或提取信息;接收一个函数做为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素
- flatMap:接收一个函数做为参数,将流中的每一个值都换成另外一个流,而后把全部的流链接成一个流
示例代码:
public class TestStreamApi { private static List<Demo> demoList = Arrays.asList( new Demo(1, "哈哈哈"), new Demo(2, "嘿嘿嘿嘿") ); public static void main(String[] args) { demoList.stream() .map(Demo::getRemark) .flatMap(TestStreamApi :: filterCharacter) .forEach(System.out::println); } public static Stream<Character> filterCharacter(String str) { List<Character> list = new ArrayList<>(); for (Character c : str.toCharArray()) { list.add(c); } return list.stream(); } }
运行结果: 哈 哈 哈 嘿 嘿 嘿 嘿
- sorted():天然排序
- sorted(Comparator c):定制排序
示例代码:
public class TestStreamApi { private static List<Demo> demoList = Arrays.asList( new Demo(5, "哈哈哈"), new Demo(2, "嘿嘿嘿嘿"), new Demo(3, "呵呵呵"), new Demo(2, "哼哼哼"), new Demo(5, "啧啧啧") ); public static void main(String[] args) { List<String> list = Arrays.asList("aaa", "bbb", "ccc"); list.stream() .sorted() .forEach(System.out::println); System.out.println("----------"); demoList.stream() .sorted((x, y) -> { if (x.getNum().equals(y.getNum())) { return x.getRemark().compareTo(y.getRemark()); } else { return x.getNum().compareTo(y.getNum()); } }) .forEach(System.out::println); } }
2-哼哼哼 2-嘿嘿嘿嘿 3-呵呵呵 5-哈哈哈 5-啧啧啧
###查找与匹配
- allMatch:检查是否匹配全部元素
- anyMatch:检查是否匹配全部元素
- noneMatch:检查是否没有匹配全部元素
- findFirst:返回第一个元素
- findAny:返回当前流中的任意元素
- count:返回流中元素的总个数
- max:返回流中的最大值
- min:返回流中的最小值
示例代码:
public class TestStreamApi2 { private static List<Demo> demoList = Arrays.asList( new Demo("张三", 18, 6666.66, Demo.Status.BUSY), new Demo("李四", 38, 3333.33, Demo.Status.FREE), new Demo("王五", 28, 5555.55, Demo.Status.FREE), new Demo("赵六", 48, 7777.77, Demo.Status.BUSY), new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION) ); public static void main(String[] args) { // 是否是全部的对象都处于BUSY状态 System.out.println(demoList.stream() .allMatch((d) -> d.getStatus().equals(Demo.Status.BUSY))); // 是否有对象处于BUSY状态 System.out.println(demoList.stream() .anyMatch((d) -> d.getStatus().equals(Demo.Status.BUSY))); // 是否没有对象处于BUSY状态 System.out.println(demoList.stream() .noneMatch((d) -> d.getStatus().equals(Demo.Status.BUSY))); // 获取工资最高的 Optional<Demo> optionalDemo1 = demoList.stream() .sorted((x, y) -> -Double.compare(x.getSalary(), y.getSalary())) .findFirst(); System.out.println(optionalDemo1.get()); // 获取随机一个空闲的 Optional<Demo> optionalDemo2 = demoList.stream() .filter((e) -> e.getStatus().equals(Demo.Status.FREE)) .findAny(); System.out.println(optionalDemo2.get()); // 总数 System.out.println(demoList.stream().count()); // 工资最高的 Optional<Demo> optionalDemo3 = demoList.stream() .max((x, y) -> Double.compare(x.getSalary(), y.getSalary())); System.out.println(optionalDemo3.get()); // 最小的工资 Optional<Double> optionalDemo4 = demoList.stream() .map(Demo::getSalary) .max(Double::compare); System.out.println(optionalDemo4.get()); } } class Demo{ // 姓名 String name; // 年龄 Integer age; // 工资 Double salary; // 状态 Status status; public Demo() {} public Demo(String name, Integer age, Double salary, Status status) { this.name = name; this.age = age; this.salary = salary; this.status = status; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Demo demo = (Demo) o; return name.equals(demo.name) && age.equals(demo.age) && salary.equals(demo.salary) && status == demo.status; } @Override public int hashCode() { return Objects.hash(name, age, salary, status); } @Override public String toString() { return "Demo{" + "name='" + name + '\'' + ", age=" + age + ", salary=" + salary + ", status=" + status + '}'; } public enum Status{ FREE, BUSY, VOCATION } }
运行结果: false true false Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION} Demo{name='李四', age=38, salary=3333.33, status=FREE} 5 Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION} 8888.88
- reduce(T identify, BinaryOperator) / reduce(BinaryOperator):能够将流中元素反复结合起来,获得一个值
示例代码:
public class TestStreamApi3 { private static List<Demo> demoList = Arrays.asList( new Demo("张三", 18, 6666.66, Demo.Status.BUSY), new Demo("李四", 38, 3333.33, Demo.Status.FREE), new Demo("王五", 28, 5555.55, Demo.Status.FREE), new Demo("赵六", 48, 7777.77, Demo.Status.BUSY), new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION) ); public static void main(String[] args) { Optional<Double> optional = demoList.stream() .map(Demo::getSalary) .reduce(Double::sum); System.out.println(optional.get()); } }
运行结果: 32222.190000000002
- collect:将流转换为其余形式。接收一个Collection接口的实现,用于给Stream中元素作汇总的方法
Collectors接口中方法的实现决定了如何对流执行收集操做(如搜集到List、Set、Map)。
- toList:把流中元素收集到List
- toSet:把流中元素收集到Set
- toCollection:把流中元素收集到建立的集合
- counting:计算流中元素的个数
- summingInt:对流中元素的整数属性求和
- averagingInt:计算流中元素Integer属性的平均值
- summarizingInt:收集流中Integer属性的统计值
- jioning:链接流中的每一个字符串
- maxBy:根据比较器选择最大值
- minBy:根据比较器选择最小值
- reducing:从一个做为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而规约成单个值
- collectingAndThen:包裹另外一个收集器,对其结果转换函数
- groupingBy:根据某个属性值对流分组,属性为K,结果为V
- partitioningBy:根据true、false进行分区
给定一个数组,方便测试:
private static List<Demo> demoList = Arrays.asList( new Demo("张三", 18, 6666.66, Demo.Status.BUSY), new Demo("李四", 38, 3333.33, Demo.Status.FREE), new Demo("王五", 28, 5555.55, Demo.Status.FREE), new Demo("赵六", 48, 7777.77, Demo.Status.BUSY), new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION) );
示例代码:
// 收集 - toList System.out.println("---------------->toList"); List<String> list = demoList.stream() .map(Demo::getName) .collect(Collectors.toList()); list.forEach(System.out::println);
运行结果: 张三 李四 王五 赵六 王二麻子
示例代码:
// 收集 - toSet System.out.println("---------------->toSet"); Set<String> set = demoList.stream() .map(Demo::getName) .collect(Collectors.toSet()); set.forEach(System.out::println);
运行结果: 李四 张三 王二麻子 王五 赵六
示例代码:
// 收集 - toCollection System.out.println("---------------->toCollection"); HashSet<String> hashSet = demoList.stream() .map(Demo::getName) .collect(Collectors.toCollection(HashSet::new)); hashSet.forEach(System.out::println);
运行结果: 李四 张三 王二麻子 王五 赵六
示例代码:
// 收集 - counting 计算总数 System.out.println("---------------->counting"); System.out.println(demoList.stream() .collect(Collectors.counting()));
运行结果: 5
示例代码:
// 收集 - summingInt 计算年龄总和 System.out.println("---------------->summingInt"); System.out.println(demoList.stream() .collect(Collectors.summingInt(Demo::getAge)));
运行结果: 190
示例代码:
// 收集 - averagingInt 平均年龄 System.out.println("---------------->averagingInt"); System.out.println(demoList.stream() .collect(Collectors.averagingInt(Demo::getAge)));
运行结果: 38.0
示例代码:
// 收集 - summarizingInt System.out.println("---------------->summarizingInt"); IntSummaryStatistics summaryStatistics = demoList.stream() .collect(Collectors.summarizingInt(Demo::getAge)); // 最大值 System.out.println(summaryStatistics.getMax()); // 平均值 System.out.println(summaryStatistics.getAverage()); // 总和 System.out.println(summaryStatistics.getSum());
运行结果: 58 38.0 190
示例代码:
// 收集 - joining 链接姓名 System.out.println("---------------->joining"); String s = demoList.stream() .map(Demo::getName) .collect(Collectors.joining(",", "开始->", "<-结束")); System.out.println(s);
运行结果: 开始->张三,李四,王五,赵六,王二麻子<-结束
示例代码:
// 收集 - maxBy 获取工资最高的人 System.out.println("---------------->maxBy"); Optional<Demo> max = demoList.stream() .collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary()))); System.out.println(max.get());
运行结果: Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}
示例代码:
// 收集 - minBy 获取最低的 System.out.println("---------------->minBy"); Optional<Double> min = demoList.stream() .map(Demo::getSalary) .collect(Collectors.minBy(Double::compare)); System.out.println(min.get());
运行结果: 3333.33
示例代码:
// 收集 - groupingBy 根据状态分组 System.out.println("---------------->groupingBy"); Map<Demo.Status, List<Demo>> group = demoList.stream() .collect(Collectors.groupingBy(Demo::getStatus)); System.out.println(group); // 多级分组 先按状态分组,在按年龄分组 Map<Demo.Status, Map<String, List<Demo>>> group2 = demoList.stream() .collect(Collectors.groupingBy(Demo::getStatus, Collectors.groupingBy((x) -> { if (x.getAge() <= 30) { return "青年"; } else if (x.getAge() <= 45) { return "中年"; } else { return "老年"; } }))); System.out.println(group2);
运行结果: {VOCATION=[Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}], FREE=[Demo{name='李四', age=38, salary=3333.33, status=FREE}, Demo{name='王五', age=28, salary=5555.55, status=FREE}], BUSY=[Demo{name='张三', age=18, salary=6666.66, status=BUSY}, Demo{name='赵六', age=48, salary=7777.77, status=BUSY}]} {VOCATION={老年=[Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}]}, FREE={青年=[Demo{name='王五', age=28, salary=5555.55, status=FREE}], 中年=[Demo{name='李四', age=38, salary=3333.33, status=FREE}]}, BUSY={青年=[Demo{name='张三', age=18, salary=6666.66, status=BUSY}], 老年=[Demo{name='赵六', age=48, salary=7777.77, status=BUSY}]}}
示例代码:
// 收集 - partitioningBy 分区 System.out.println("---------------->partitioningBy"); Map<Boolean, List<Demo>> partition = demoList.stream() .collect(Collectors.partitioningBy((x) -> x.getAge() > 30)); System.out.println(partition);
运行结果: {false=[Demo{name='张三', age=18, salary=6666.66, status=BUSY}, Demo{name='王五', age=28, salary=5555.55, status=FREE}], true=[Demo{name='李四', age=38, salary=3333.33, status=FREE}, Demo{name='赵六', age=48, salary=7777.77, status=BUSY}, Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}]}
原文出处:https://www.cnblogs.com/fx-blog/p/11745205.html