流API--流的收集
2015-11-09 16:33
295 查看
前面的一系列博客中,我们都是从一个集合中拿到一个流,但是有时候需要执行反操作,就是从流中获得集合。实际编码中,当我们处理完流后,我们通常想查看下结果,而不是将他们聚合成一个值。我们可以调用iterator方法来生成一个传统风格的迭代器,用于访问元素。
1,将流中的元素收集到一个数组中,调用toArray()方法即可
由于无法在运行时创建一个泛型数组,所以调用toArray()方法将返回一个object[]数组。如果我们希望得到一个正确的数组,可以将类型传递给数组的构造函数toArray(String[]::new)。
2,将流中的元素收集到一个集合中。
流API提供了一个collect()方法,我们可以对比stream()方法,来很简单的实现集合和流的互相转换。
翻一下API说明文档,上面是这么定义这2个方法的:
关于Collector接口我们了解下好了,这个接口的申明如下:
interface Collector<T,A,R>,R指定结果的类型,T指定调用流的元素类型,内部累积类型由A指定。
Collectors类为了我们定义了一些可以直接使用的静态收集器方法,这是一个不可变类,我们一般使用toList()和toSet()方法,如下所示:
toList()方法返回的收集器可用于将元素收集到一个list中,toSet()方法返回的收集器可用于将元素收集到一个Set中。例如,我们现在想要把元素收集到一个list中,可以向下面这样子调用:
上面的整理我们使用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指定两个将要被合并的集合。
具体的使用看下面代码:
3,将流中的元素收集到一个map中
和上面的处理list一样,使用Collectors的toMap()方法就可以将一个流中的元素收集到一个map中。该方法有2个参数,分别用来生成map的键和值。
关于这点要注意的是,如果有相同的元素拥有相同的键,那么收集方法就会报错:java.lang.IllegalStateException
我们可以提供第3个函数参数,根据已有的值和新值来决定键的值,从而重新该行为。
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)); } }
相关文章推荐
- Win8系统换Win7前格式化磁盘需要做的事情。
- ListView之头部浮动效果
- 为什么现在改用int.TryParse了
- linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例
- 网站
- oracle 查询杀死死锁方案
- 曹欢欢:产品的数据思维PPT
- iOS9 相册的进入及显示图片
- SPI
- 去除C++String的首尾空格
- Oracle CASE WHEN 用法介绍
- 管道 一些知识
- 7-11便利店的陈列心理学
- netty的ip过滤
- 设计美学
- item 1:理解template类型的推导
- Python 常用函数time.strftime()简介
- poj1426Find The Multiple(AC)
- css--960框架
- 第9周 项目4 - 广义表算法库及应用