流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 -- 读取数据 ...
随机推荐
- Java 控制台输入数字 输出乘法表(代码练习)
最近,回忆了一些刚学习Java时经常练习的一些小练习题.感觉还是蛮有趣的,在回顾时想起好多学习时的经历和坎坷,一道小小的练习题要研究半天,珍重过往,直面未来.下面贡献代码,Java 控制台输入数字 输 ...
- ActiveMQ入门介绍
1.JMS简介 JMS的全称是Java Message Service,即Java消息服务.它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息.把它应用到实际的业务需 ...
- 有关求任意一个正整数的n的因数的个数的求解思路
已知条件:n=p1^a1xp2^a2xp3^a3........xpk^ak;求解n的因数的个数: 求解的主要思想:递归 设所有的因数的个数为U1: 则U1会等于什么呢? 不妨设求得p2^a2xp3^ ...
- app额外后台运行操作
//在视图中运行操作中进行周期操作 - (void)applicationDidEnterBackground:(UIApplication *)application { [self beingBa ...
- jsp+struts2登录框架模板
一.建立一个名叫jsp_struts2的项目 二.导入jar包 如上图:jar包导入在WebContent/WEB-INF/lib下 三.建立一个LoginAction类 LoginAction类的s ...
- 一个标准的WebView示例
xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android= ...
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](一)
前言 大家好,我是Rector 从今天开始,Rector将为大家推出一个关于创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]的文章系列, ...
- UVA 11292 Dragon of Loowater(简单贪心)
Problem C: The Dragon of Loowater Once upon a time, in the Kingdom of Loowater, a minor nuisance tur ...
- BZOJ3237: [Ahoi2013]连通图
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3237 cdq分治+缩点. 可以每次处理的时候把除l~r之外的边的端点都连起来.然后去跑cdq分 ...
- SpringMVC整合Shiro权限框架
尊重原创:http://blog.csdn.net/donggua3694857/article/details/52157313 最近在学习Shiro,首先非常感谢开涛大神的<跟我学Shiro ...