很多时候,将一个流的元素映射到另外一个流很有帮助。映射操作最具代表的就是map()方法。实际编码中,我们会经常用到,所以这里专门整理一篇博客。
考虑如下情景,对于一个包含了姓名,电话,年龄等属性构成的数据库的流,我们现在只想处理这个流中的姓名属性。或者是我们希望对流中一些元素做一些转换,比如只针对上面的姓名做一些处理。
map()方法签名如下:
OK,现在我们面向对象来使用map()来对流做一些映射。
map()方法是一个中间操作,所以可以将多个中间操作放到管道中,所以很容易创建非常强大的操作。在创建数据库风格的查询时,这种过滤操作十分常见。随着使用流API的经验增多,这种链式操作可以用来在数据流上创建非常复杂的查询,合并和选择操作。看下面一个例子:
流API还提供了flatMap等一系列方法,来处理原始流中的每个元素映射到结果流中的多个元素这种情况。
这里介绍一个计算机科学中的基本概念。假设我们有一个泛型G和2个函数,即从T到G<U>的f函数和从U到G<U>的g方法。那么我们就可以将他们进行组合,即通过使用flatMap方法,先应用f函数,然后再应用g函数。这是Monads理论的一个关键概念。
在这里我们回顾下Optional类的flatMap方法,假设你有一个返回Optional<T>的方法f,并且目标类型T有一个会返回Optional<U>的方法g。如果他们都是普通的方法,你可能会考虑通过调用s.f().g()将他们组合起来,但是这种组合在这里是行不通的。因为s.f()方法返回的是Optional<T>,而不是T。但是我们可以调用Optional<U> = s.f().flatMap(T::g),如果s.f()存在,那么就会继续调用g,否则返回一个空的Optional<U>。
通过上面的回顾,我们可以简单的理解这个flatMap的用法,在Stream流中就是说不是直接处理这个流的,而是处理这个流里面的元素的,在Optional类中就是说不是直接处理这个类的,而是处理这个类里面的包含的对象的,他们最终都会返回一个流或者一个Optional容器的。OK,现在通过一段代码来演示下这个api的用法:
考虑如下情景,对于一个包含了姓名,电话,年龄等属性构成的数据库的流,我们现在只想处理这个流中的姓名属性。或者是我们希望对流中一些元素做一些转换,比如只针对上面的姓名做一些处理。
map()方法签名如下:
<R> Stream<R> map(Function<? super T, ? extends R> mapper)Function是一个函数式接口,用来将T类型的元素处理成R类型,这里不做赘述了。先来看一个例子吧:
public static void main(String[] args) throws Exception { List<Double> list = new ArrayList<>(4); list.add(1.5); list.add(2.3); list.add(3.0); list.add(4.1); list.parallelStream().map((a) -> Math.sqrt(a)).forEach(System.out::println); System.out.println(list.parallelStream().map((a) -> Math.sqrt(a)).reduce(1.0, (a, b) -> a * b)); }
OK,现在我们面向对象来使用map()来对流做一些映射。
package com.linkin.maven.mavenTest; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; import com.google.common.collect.Lists; public class Test { public static void main(String[] args) throws Exception { List<NameAndAge> list = new ArrayList<>(4); list.add(new NameAndAge("关羽", 21)); list.add(new NameAndAge("张飞", 22)); list.add(new NameAndAge("赵云", 23)); list.add(new NameAndAge("典韦", 24)); list.parallelStream().map((a) -> a.getName()).forEach(System.out::println); list.parallelStream().map((a) -> new NameOnly(a.getName())).forEach(System.out::println); } } //模拟一个有2个属性的对象 class NameAndAge { private String name; private Integer age; /** * @param name * @param age */ public NameAndAge(String name, Integer age) { this.name = name; this.age = age; } 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; } } //模拟一个只有一个属性的对象 class NameOnly { private String name; public NameOnly(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
map()方法是一个中间操作,所以可以将多个中间操作放到管道中,所以很容易创建非常强大的操作。在创建数据库风格的查询时,这种过滤操作十分常见。随着使用流API的经验增多,这种链式操作可以用来在数据流上创建非常复杂的查询,合并和选择操作。看下面一个例子:
public static void main(String[] args) throws Exception { List<NameAndAge> list = new ArrayList<>(4); list.add(new NameAndAge("s关羽", 21)); list.add(new NameAndAge("s张飞", 22)); list.add(new NameAndAge("s赵云", 23)); list.add(new NameAndAge("w典韦", 24)); //使用链式操作,现在只想获得一个魏国的武将的姓名的流 list.parallelStream().map((a) -> a.getName()).filter((a) -> a.startsWith("w")).forEach(System.out::println); }
- 基本类型流的过滤
IntStream mapToInt(ToIntFunction<? super T> mapper); LongStream mapToLong(ToLongFunction<? super T> mapper); DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);这些api很简单,我们来看一个例子好了
/** * @创建时间: 2015年11月5日 * @相关参数: @param args * @相关参数: @throws Exception * @功能描述: mapToInt()方法演示 */ 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); //产生一个新的流,该流包含不小于原始流中的最小整数 list.parallelStream().mapToInt((a) -> (int) Math.ceil(a)).forEachOrdered(System.out::println); }
流API还提供了flatMap等一系列方法,来处理原始流中的每个元素映射到结果流中的多个元素这种情况。
这里介绍一个计算机科学中的基本概念。假设我们有一个泛型G和2个函数,即从T到G<U>的f函数和从U到G<U>的g方法。那么我们就可以将他们进行组合,即通过使用flatMap方法,先应用f函数,然后再应用g函数。这是Monads理论的一个关键概念。
在这里我们回顾下Optional类的flatMap方法,假设你有一个返回Optional<T>的方法f,并且目标类型T有一个会返回Optional<U>的方法g。如果他们都是普通的方法,你可能会考虑通过调用s.f().g()将他们组合起来,但是这种组合在这里是行不通的。因为s.f()方法返回的是Optional<T>,而不是T。但是我们可以调用Optional<U> = s.f().flatMap(T::g),如果s.f()存在,那么就会继续调用g,否则返回一个空的Optional<U>。
通过上面的回顾,我们可以简单的理解这个flatMap的用法,在Stream流中就是说不是直接处理这个流的,而是处理这个流里面的元素的,在Optional类中就是说不是直接处理这个类的,而是处理这个类里面的包含的对象的,他们最终都会返回一个流或者一个Optional容器的。OK,现在通过一段代码来演示下这个api的用法:
public static void main(String[] args) { List<String> list = new ArrayList<>(3); list.add("张飞"); list.add("关羽"); list.add("赵云"); Stream<String> stream = list.stream(); //下面的过滤:[...[张,飞],[关,羽]...] Stream<Stream<Character>> result = stream.map(Test::characterStream); result.forEach(System.out::println); //下面的过滤[张,飞,关,羽,赵,云] list.stream().flatMap(Test::characterStream).forEach(System.out::println); } //模拟一个方法,返回一个包含多个元素的流 public static Stream<Character> characterStream(String str) { List<Character> list = new ArrayList<>(str.length()); for (Character character : str.toCharArray()) { list.add(character); } return list.stream(); }
风流子弟曾少年,多少老死江湖前。。。