流
此处的流(Stream)与io中的输入流(InputStream)与输出流(OutputStream)是不同的概念,与实时处理数据的流也是不同的概念,但它们也有相似之处。
Stream是对集合类的增强,它将List、Map等集合作为数据源,串行或并行地操作集合类,这些操作包括遍历(foreach)、过滤(filter)、排序(sort)、匹配(match)、映射(map)、计数(count)等,上述操作分为两种类型:
1、中间操作:该操作将会计算数据,返回计算后的流
2、终端操作:该操作会关闭流,返回最终数据
为了进行运算,Stream操作被放入到流管道中,流管道由数据源(可以是数组、集合、I/O通道等)、转换流的中间操作(比如filter)、返回数据结果的最终操作组成(比如count和foreach)。
流管道示意图:
Java中流特性:
- 不是数据结构
- 并不储存数据,所有的操作从源抓取
- 不会影响源数据
- 不支持索引访问(但可以使用IntStream曲线救国)
- 惰性
- 只有最终操作被启动时,才会计算源数据
- 只有当需要的时候才使用源元素(提供源数据的元素)
- 并行
BaseStream
所有的流都继承此接口
java // 继承自AutoCloseable,说明流都是自动关闭的 public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable { // 下面是所有流都拥有的方法 // 返回当前流元素的迭代器(终端操作) Iterator<T> iterator(); // 返回当前流元素的可切割迭代器(终端操作) Spliterator<T> spliterator(); // 是否并行流 boolean isParallel(); // 返回当前流的串行流,若当前流已经是串行或流已经被修改为串行,返回自己 S sequential(); // 返回当前流的并行流,若当前流已经是并行或流已经被修改为并行,返回自己 S parallel(); // 返回当前流的乱序流,若当前流已经是乱序或流已经被修改为乱序,返回自己 S unordered(); // 返回添加了额外的流关闭处理器的流,当close()方法执行的时候调用。 // 所有的流关闭处理器都会被执行,即使某处理器发生异常, S onClose(Runnable closeHandler); void close(); }
Java基于BaseStream提供了众多数据流的封装,其中基于原始数据类型的数据流封装较为常用,比如:IntStream、DoubleStream、LongStream、
Stream
继承自BaseStream
Stream API如下图:
Java中流特性:
- 不是数据结构
- 并不储存数据,所有的操作从源抓取
- 不会影响源数据
- 不支持索引访问(但可以使用IntStream曲线救国)
- 惰性
- 只有最终操作被启动时,才会计算源数据
- 只有当需要的时候才使用源元素(提供源数据的元素)
- 并行
生成流的几种方式
1、数组方式
java // 1. Stream aryStream = Stream.of(ary); // 2. Arrays.stream(ary);
2、集合方式
java // 串行 List<String> list = new ArrayList<>(); list.add("1"); list.add("1"); list.add("1"); Stream stream = list.stream(); // 并行 List<String> list2 = new ArrayList<>(); list2.add("1"); list2.add("1"); list2.add("1"); Stream stream = list.parallelStream();
3、静态工厂
java // 这种方式可以解决下标问题 int[] ary = {1,2,3,4,5,6,7,8,9}; IntStream.range(0,ary.length).forEach(System.out::println);// 不包含10 IntStream.rangeClosed(0,ary.length).forEach(System.out::println);// 包含10
4、I/O
java BufferedReader bufferedReader = new BufferedReader(new FileReader("project.properties")); Stream<String> stream = bufferedReader.lines();
5、其他
java // 1. Random random = new Random(); IntStream stream1 = random.ints(); // 2. Path path = Paths.get("D:\\记事本.txt"); Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
常用操作示例
下文示例中使用到的Widget实体及集合
java class Widget{ private String color; private int weight; // ...省略g&t } private Widget w1 = new Widget("RED",20); private Widget w2 = new Widget("GREEN",20); private Widget w3 = new Widget("GRAY",20); private List<Widget> widgetList = new ArrayList<>(); { widgetList.add(w1); widgetList.add(w2); widgetList.add(w3); }
filter
java @Test public void stream(){ // 统计红色小组件个数 System.out.println(widgetList.stream().filter(w -> w.getColor().equals("RED")).count()); // 统计红色小组件总重 System.out.println( widgetList.stream().filter(w -> w.getColor().equals("RED")) // w -> w.getWeight() // method reference 使用 Widget::getWeight 替代 w -> w.getWeight // 方法引用可以用来替换λ表达式 .mapToInt(Widget::getWeight) .sum() ); }
filter的入参是谓词 Predicate ,如果一个操作使用频繁,我们可以先写好一个 Predicate ,之后使用它就可以了
java /*谓词,filter方法接收的编程式函数(functional interface)*/ private static Predicate<Widget> isRedWidget(){ return widget -> widget.getColor().equals("RED"); } /*filter forEach forEachRemaining*/ @Test public void stream(){ // predicate List<Widget> newWidgets = widgetList.stream().filter(isRedWidget()).collect(Collectors.toList()); newWidgets.forEach(System.out::println); newWidgets.iterator().forEachRemaining(System.out::println); } // 输出 com.baosight.test.StreamTest$Widget@26f67b76 com.baosight.test.StreamTest$Widget@26f67b76
map
java @Test public void map(){ String[] ary = {"Hello","world","John sena"}; // peek不是最终操作,所以下面这条语句不会输出任何东西 // 这就验证了前面提到的Streams are lazy Arrays.stream(ary).map(String::toUpperCase).peek(word -> System.out.println("Mapped value:"+word)); Arrays.stream(ary).map(String::toUpperCase).peek(word -> System.out.println("Mapped value:"+word)).count(); } // 输出 Mapped value:HELLO Mapped value:WORLD Mapped value:JOHN SENA
collect
java @Test public void stream(){ List<Integer> list = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).collect(Collectors.toList()); System.out.println(list.toString()); String string = Stream.of("1","2").collect(Collectors.joining(",")); System.out.println(string); Map widgetMap = widgetList.stream().collect(Collectors.groupingBy(Widget::getColor)); // 收集行为可以级联 Map widgetMap2 = widgetList.stream().collect(Collectors.groupingBy(Widget::getColor,Collectors.groupingBy(Widget::getWeight))); System.out.println(widgetMap.toString()); } // 输出 [1, 2, 3, 45, 6, 7, 8, 5, 435] 1,2 {RED=[com.baosight.test.StreamTest$Widget@61a485d2], GRAY=[com.baosight.test.StreamTest$Widget@39fb3ab6], GREEN=[com.baosight.test.StreamTest$Widget@6276ae34]}
reduce
java /*Instant LongStream.rangeClosed*/ @Test public void stream(){ // instant类用于获取时间线上的时间点 Instant start = Instant.now(); // 计算范围内的和 long r = LongStream.rangeClosed(0, 100000) .parallel()// 并行流 // .sequential() 串行流 .reduce(0, Long::sum); Instant end = Instant.now(); // 迭代器 forEach和forEachRemaining 的区别: // forEach可以多次调用,对元素多次处理 // forEachRemaining对所有元素只处理一次 // 所以在第二次调用同一个迭代器的forEachRemaining方法时无作为 Iterator iterator = newWidgets.iterator(); iterator.forEachRemaining(System.out::println); iterator.forEachRemaining(System.out::println); } // 输出 5000050000 本次执行耗时:62
sort
java /*sorted*/ @Test public void stream(){ // 排序 Integer i[] = {1,2,3,5,6,7,9,45,9,324,22}; List<Integer> integers = Arrays.asList(i); integers.stream().sorted().forEach(System.out::println); } // 输出 1 2 3 5 6 7 9 9 22 45 324
distinct
java /*distinct*/ @Test public void stream(){ // 去重 Integer i[] = {1,2,2,2,27,2,2,9,324,22}; List<Integer> integers = Arrays.asList(i); integers.stream().distinct().forEach(System.out::println); } // 输出 1 2 27 9 324 22
下标
java @Test /*IntStream.range/rangeClosed*/ public void stream(){ int[] ary = {1,2,3,4,5,6,7,8,9}; // Stream aryStream = Stream.of(ary); // Arrays.stream(ary); //IntStream 可以用来当作遍历的下标 IntStream.range(0,ary.length).forEach(System.out::println);// 不包含10 IntStream.rangeClosed(0,ary.length).forEach(System.out::println);// 包含10 IntStream.range(0,ary.length).forEach( i -> System.out.println(i*666)); }
flatMap
java class Order{ private String orderNo; private String orderName; private List<OrderLineItem> lineItems; //...省略g&t } class OrderLineItem{ private String lineNo; private String lineName; //...省略g&t } @Test /*produce a new stream*/ public void stream(){ List<Order> orders = new ArrayList<>(); List<OrderLineItem> lineItems = new ArrayList<>(); lineItems.add(new OrderLineItem("1", "one")); lineItems.add(new OrderLineItem("2", "two")); lineItems.add(new OrderLineItem("1", "three")); lineItems.add(new OrderLineItem("1", "four")); lineItems.add(new OrderLineItem("1", "five")); orders.add(new Order("1","one",lineItems)); orders.add(new Order("2", "two", lineItems)); orders.add(new Order("3", "three", lineItems)); // orders的流中将所有orders的lineItems组装起来返回一个新的流, // 这个流中有所有order的所有orderLineItem(在当前测试方法中有15个,3*5) List data = orders.stream().flatMap(order -> order.getLineItems().stream()).collect(Collectors.toList()); System.out.println(data.size()); } // 输出 15
peek
java /*peek*/ @Test public void stream(){ // 就像名字一样,窥视 233 List<String> list = Stream.of("one","two","three","four","five") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value:"+e)) .map(String::toUpperCase) .peek(e -> System.out.println("Maped value:"+e)) .collect(Collectors.toList()); } // 输出 Filtered value:three Maped value:THREE Filtered value:four Maped value:FOUR Filtered value:five Maped value:FIVE
anyMatch/allMatch/noneMatch
java @Test public void match() { // 匹配 boolean match = widgetList.stream().anyMatch(isRedWidget()); boolean match2 = widgetList.stream().allMatch(isRedWidget()); boolean match3 = widgetList.stream().noneMatch(isRedWidget()); System.out.println(match); System.out.println(match2); System.out.println(match3); } // 输出 true false false
limit、skip
java /*limit skip*/ @Test public void stream(){ // 两个作用类似,一个限制n个元素,一个跳过n个元素 List<Integer> list = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).limit(5).collect(Collectors.toList()); System.out.println(list.toString()); List<Integer> list2 = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).skip(5).collect(Collectors.toList()); System.out.println(list.toString()); } // 输出 [1, 2, 3, 45, 6] [1, 2, 3, 45, 6]
min、max
java @Test public void minAndMax() { Comparator comparator = (o1, o2) -> (int) o1 > (int) o2 ? 1 : -1; Optional optional = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).min(comparator); System.out.println(optional.get()); Optional optional2 = Stream.of(1, 2, 3, 45, 6, 7, 8, 5, 435).max(comparator); System.out.println(optional2.get()); } // 输出 1 435
findFirst/findAny
java @Test public void find() { // findFirst返回流中第一个元素 // findAny返回流中任意元素 Optional optional = widgetList.stream().findFirst(); Optional optional2 = widgetList.stream().findAny(); Widget widget = (Widget) optional.get(); Widget widget2 = (Widget) optional2.get(); System.out.println(widget.getColor()); System.out.println(widget2.getColor()); }
toArray
java /*toArray*/ @Test public void steam(){ Widget[] widgets = widgetList.stream().filter(widget -> widget.getColor().equals("RED")).toArray(Widget[]::new); }