流API--流的收集
前面的一系列博客中,我们都是从一个集合中拿到一个流,但是有时候需要执行反操作,就是从流中获得集合。实际编码中,当我们处理完流后,我们通常想查看下结果,而不是将他们聚合成一个值。我们可以调用iterator方法来生成一个传统风格的迭代器,用于访问元素。
- 1,将流中的元素收集到一个数组中,调用toArray()方法即可
由于无法在运行时创建一个泛型数组,所以调用toArray()方法将返回一个object[]数组。如果我们希望得到一个正确的数组,可以将类型传递给数组的构造函数toArray(String[]::new)。
public static void main(String[] args)
{
Stream<String> stream = Stream.of("林肯", "冰儿");
String[] array = stream.toArray(String[]::new);
for (String str : array)
{
System.out.println(str);
}
}
- 2,将流中的元素收集到一个集合中。
流API提供了一个collect()方法,我们可以对比stream()方法,来很简单的实现集合和流的互相转换。
翻一下API说明文档,上面是这么定义这2个方法的:
<R,A> R collect(Collector<? super T,A,R> collector):Performs a mutable reduction operation on the elements of this stream using a Collector.
<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner):Performs a mutable reduction operation on the elements of this stream.
关于Collector接口我们了解下好了,这个接口的申明如下:
interface Collector<T,A,R>,R指定结果的类型,T指定调用流的元素类型,内部累积类型由A指定。
Collectors类为了我们定义了一些可以直接使用的静态收集器方法,这是一个不可变类,我们一般使用toList()和toSet()方法,如下所示:
public static <T> Collector<T, ?, List<T>> toList()
{
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, (left, right) ->
{
left.addAll(right);
return left;
} , CH_ID);
} public static <T> Collector<T, ?, Set<T>> toSet()
{
return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add, (left, right) ->
{
left.addAll(right);
return left;
} , CH_UNORDERED_ID);
}
toList()方法返回的收集器可用于将元素收集到一个list中,toSet()方法返回的收集器可用于将元素收集到一个Set中。例如,我们现在想要把元素收集到一个list中,可以向下面这样子调用:
public static void main(String[] args) throws Exception
{
List<Double> list = new ArrayList<>(4);
list.add(1.1);
list.add(2.5);
list.add(3.0);
list.add(4.8);
Stream<Double> parallelStream = list.parallelStream();
List<Double> collect = parallelStream.collect(Collectors.toList());
collect.forEach(System.out::println);
}
上面的整理我们使用Collectors的静态方法比较方便,当然我们也看到了上面的collect方法还有另外一个重载,我们使用这个版本可以对收集过程做更多的控制。
collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
关于这个方法签名多说几句,上面方法中的3个参数:
supplier:表示一个指向可变存储对象的引用;后面2个参数都是BiConsumer<R,R> 类型的,这个函数式接口表示对2个对象进行处理,它里面的抽象方法签名如下:void accept(T obj1,U obj2),对于上面第2个参数,obj1指定目标集合,obj2指定要添加到该集合中的元素,对于上面的第3个参数,obj1和obj2指定两个将要被合并的集合。
具体的使用看下面代码:
public static void main(String[] args) throws Exception
{
List<Double> list = new ArrayList<>(4);
list.add(1.1);
list.add(2.5);
list.add(3.0);
list.add(4.8);
Stream<Double> parallelStream = list.parallelStream();
//使用Lambda表达式
parallelStream.collect(() -> new LinkedList<>(), (MyList, element) -> MyList.add(element), (listA, listB) -> listA.addAll(listB))
.forEach(System.out::println);
//使用方法引用,直接使用被消费过的流报错stream has already been operated upon or closed,所以要重新获得流
List<Double> list1 = list.parallelStream().collect(LinkedList::new,LinkedList::add,LinkedList::addAll);
list1.forEach(System.out::println);
}
- 3,将流中的元素收集到一个map中
和上面的处理list一样,使用Collectors的toMap()方法就可以将一个流中的元素收集到一个map中。该方法有2个参数,分别用来生成map的键和值。
public class Test
{ public static void main(String[] args)
{
Stream<Person> stream = Stream.of(new Person("1", "林肯"), new Person("2", "冰儿"));
Map<String, String> collect = stream.collect(Collectors.toMap(Person::getId, Person::getName));
for (String string : collect.keySet())
{
System.out.println(string + "-->" + collect.get(string));
} for (Map.Entry<String, String> entry : collect.entrySet())
{
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
System.out.println("==========华丽丽的分割线============"); Stream<Person> stream1 = Stream.of(new Person("1", "林肯"), new Person("2", "冰儿"));
//如果要获得原来的元素,使用Function.identity()就OK啦
Map<String, Person> map = stream1.collect(Collectors.toMap(Person::getId, Function.identity()));
for (String string : map.keySet())
{
System.out.println(string + "-->" + map.get(string).toString());
}
} } class Person
{
private String id;
private String name; public Person(String id, String name)
{
this.id = id;
this.name = name;
} public String getId()
{
return id;
} public void setId(String id)
{
this.id = id;
} public String getName()
{
return name;
} public void setName(String name)
{
this.name = name;
} @Override
public String toString()
{
return "Person [id=" + id + ", name=" + name + "]";
} }
关于这点要注意的是,如果有相同的元素拥有相同的键,那么收集方法就会报错:java.lang.IllegalStateException
public static void main(String[] args)
{
Stream<Person> stream = Stream.of(new Person("1", "林肯"), new Person("1", "冰儿"));
//下面代码报错,java.lang.IllegalStateException:
Map<String, String> collect = stream.collect(Collectors.toMap(Person::getId, Person::getName));
for (String string : collect.keySet())
{
System.out.println(string + "-->" + collect.get(string));
} }
那么怎么办呢?
我们可以提供第3个函数参数,根据已有的值和新值来决定键的值,从而重新该行为。
public static void main(String[] args)
{
Stream<Person> stream = Stream.of(new Person("1", "林肯"), new Person("1", "冰儿"));
//下面代码输出:1-->林肯冰儿
Map<String, String> collect = stream.collect(Collectors.toMap(Person::getId, Person::getName,(value1,value2)->value1+value2));
for (String string : collect.keySet())
{
System.out.println(string + "-->" + collect.get(string));
} }
流API--流的收集的更多相关文章
- JAVA8给我带了什么——流的概念和收集器
到现在为止,笔者不敢给流下定义,从概念来讲他应该也是一种数据元素才是.可是在我们前面的代码例子中我们可以看到他更多的好像在表示他是一组处理数据的行为组合.这让笔者很难去理解他的定义.所以笔者不表态.各 ...
- 响应式流API的构建基础
下面三个重要的概念是响应式流API的构建基础: 发布者是事件的发送方,可以向它订阅. 订阅者是事件订阅方. 订阅将发布者和订阅者联系起来,使订阅者可以向发布者发送信号. http://www.info ...
- java8-Stream流API
一回顾与说明 经过前面发布的三章java8的博客,你就懂得了我们为什么要用Lamda表达式,Lamda表达式的原理与函数式接口的关系,从Lamda表达式到方法引用和构造引用. 想要学Stream流你必 ...
- Python 完美诠释"高内聚"概念的 IO 流 API 体系结构
1. 前言 第一次接触 Python 语言的 IO API 时,是惊艳的.相比较其它语言所提供的 IO 流 API . 无论是站在使用者的角度还是站在底层设计者的角度,都可以称得上无与伦比. 很多人在 ...
- 详解ROMA Connect API 流控实现技术
摘要:本文将详细描述API Gateway流控实现,揭开高性能秒级流控的技术细节. 1.概述 ROMA平台的核心系统ROMA Connect源自华为流程IT的集成平台,在华为内部有超过15年的企业业务 ...
- Java 基础 IO流(转换流,缓冲)
一,前言 在学习字符流(FileReader.FileWriter)的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者OutputStr ...
- java 文件字节和字符流 缓冲流
流的原理 1) 在 Java 程序中,对于数据的输入/输出操作以“流”(stream) 方式进行:2) J2SDK 提供了各种各样的“流”类,用以获取不同种类的数据:程序中通过标准的方法输入或输出数据 ...
- [源码]ObjectIOStream 对象流 ByteArrayIOStream 数组流 内存流 ZipOutputStream 压缩流
1.对象流 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File ...
- IO流03_流的分类和概述
[概述] Java的IO流是实现输入/输出的基础,它可以方便的实现数据的输入/输出操作. Java中把不同的输入/输出源(键盘.文件.网络连接)抽象表述为"流"(Stream). ...
- Java基础知识强化之IO流笔记41:字符流缓冲流之复制文本文件案例02(使用 [ newLine() / readLine() ] )(重要)
1. 使用字符流缓冲流的特殊功能 [ newLine() / readLine() ] 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中 数据源: a.txt -- 读取数据 ...
随机推荐
- DNN论文分享 - Item2vec: Neural Item Embedding for Collaborative Filtering
前置点评: 这篇文章比较朴素,创新性不高,基本是参照了google的word2vec方法,应用到推荐场景的i2i相似度计算中,但实际效果看还有有提升的.主要做法是把item视为word,用户的行为序列 ...
- 实现数组元素互换位置(乘机理解java参数传递)
Java中函数参数是按值传递的,在实现数组元素互换位置之前,我想先说一下Java函数参数传递过程.一般情况下我们会把参数分为基本数据类型和引用数据类型,然后分别来讲参数传递,因为他们的外在表现似乎是不 ...
- 关于JS中变量提升的规则和原理的一点理解
关于变量提升,以前在一些教程和书籍上都听到过,平时开发中也知道有这个规律,但是今天突然在一个公开课中听到时,第一反应时一脸懵逼,然后一百度,瞬间觉得好熟悉啊,差点被这个概念给唬住了,不信我给你 ...
- meta标签有何作用?一起来学习一下
平日里总是沉迷于写页面写组件思考业务逻辑,解决冲突找出bug,猛的发现躲在head标签里的一大串标签时什么?这么多meta标签好多居然都不知其存在的意义.所以决定记录一下学习到的知识点. 先搞明白以上 ...
- 12、ABPZero系列教程之拼多多卖家工具 拼团提醒功能登录拼多多实现
上篇文章已经完成了整个拼多多拼团提醒功能,本篇继续完成拼多多帐号登录,拼多多帐号登录的目的是为了获取拼团商品的SKU和订单号,便于商家备货. 以下是拼多多官方的后台登录,要实现的功能并不是直接在这里登 ...
- CountDownLatch源码解析
一.CountDownLatch介绍 CountDownLatch是在jdk1.5被引入的,它主要是通过一个计数器来实现的,当在初始化该类的构造函数时,会事先传入一个状态值,之后在执行await方法后 ...
- Codeforces Round #301 (Div. 2)(A,【模拟】B,【贪心构造】C,【DFS】)
A. Combination Lock time limit per test:2 seconds memory limit per test:256 megabytes input:standard ...
- Codeforces Round #300(A.【字符串,多方法】,B.【思维题】,C.【贪心,数学】)
A. Cutting Banner time limit per test:2 seconds memory limit per test:256 megabytes input:standard i ...
- the quick brown fox jumps over the lazy dog
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
- 关于Swing窗体有时候要放大缩小边框才能显示问题?
有时候会出现编写swing窗体后添加的组件在run之后显示不出来的问题.如图: 搜了下解决办法.此时如果是程序里面有panel组件的话,应该这样: labels[i] = new Label(lett ...