很多时候,将一个流的元素映射到另外一个流很有帮助。映射操作最具代表的就是map()方法。实际编码中,我们会经常用到,所以这里专门整理一篇博客。

考虑如下情景,对于一个包含了姓名,电话,年龄等属性构成的数据库的流,我们现在只想处理这个流中的姓名属性。或者是我们希望对流中一些元素做一些转换,比如只针对上面的姓名做一些处理。

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);
}
  • 基本类型流的过滤

除了上面的整理,map()方法还有另外3个版本,返回基本类型的流。

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();
}

流API--流的映射的更多相关文章

  1. java8-Stream流API

    一回顾与说明 经过前面发布的三章java8的博客,你就懂得了我们为什么要用Lamda表达式,Lamda表达式的原理与函数式接口的关系,从Lamda表达式到方法引用和构造引用. 想要学Stream流你必 ...

  2. 详解ROMA Connect API 流控实现技术

    摘要:本文将详细描述API Gateway流控实现,揭开高性能秒级流控的技术细节. 1.概述 ROMA平台的核心系统ROMA Connect源自华为流程IT的集成平台,在华为内部有超过15年的企业业务 ...

  3. 响应式流API的构建基础

    下面三个重要的概念是响应式流API的构建基础: 发布者是事件的发送方,可以向它订阅. 订阅者是事件订阅方. 订阅将发布者和订阅者联系起来,使订阅者可以向发布者发送信号. http://www.info ...

  4. Python 完美诠释"高内聚"概念的 IO 流 API 体系结构

    1. 前言 第一次接触 Python 语言的 IO API 时,是惊艳的.相比较其它语言所提供的 IO 流 API . 无论是站在使用者的角度还是站在底层设计者的角度,都可以称得上无与伦比. 很多人在 ...

  5. Java 基础 IO流(转换流,缓冲)

    一,前言 在学习字符流(FileReader.FileWriter)的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者OutputStr ...

  6. IO流(字节流,字符流,缓冲流)

    一:IO流的分类(组织架构) 根据处理数据类型的不同分为:字节流和字符流 根据数据流向不同分为:输入流和输出流   这么庞大的体系里面,常用的就那么几个,我们把它们抽取出来,如下图:   二:字符字节 ...

  7. java 文件字节和字符流 缓冲流

    流的原理 1) 在 Java 程序中,对于数据的输入/输出操作以“流”(stream) 方式进行:2) J2SDK 提供了各种各样的“流”类,用以获取不同种类的数据:程序中通过标准的方法输入或输出数据 ...

  8. [源码]ObjectIOStream 对象流 ByteArrayIOStream 数组流 内存流 ZipOutputStream 压缩流

    1.对象流 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File ...

  9. IO流03_流的分类和概述

    [概述] Java的IO流是实现输入/输出的基础,它可以方便的实现数据的输入/输出操作. Java中把不同的输入/输出源(键盘.文件.网络连接)抽象表述为"流"(Stream). ...

  10. Java基础知识强化之IO流笔记41:字符流缓冲流之复制文本文件案例02(使用 [ newLine() / readLine() ] )(重要)

    1. 使用字符流缓冲流的特殊功能 [ newLine() / readLine() ] 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中  数据源: a.txt -- 读取数据 ...

随机推荐

  1. Java框架之Hibernate(三)

    本文主要讲解: 1 级联 cascade 关键字 2 级联删除 3 inverse 关键字 4 懒加载 5 缓存的模拟 6 Hibernate 的一级缓存 7 Hibernate 的二级缓存 一.级联 ...

  2. 浅谈JavaScript的面向对象程序设计(四)

    本文继续讲解JavaScript的面向对象程序设计.继承是面向对象语言中的一个基本概念,面向对象语言支持两种继承实现方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.但是在 ...

  3. MySQL innodb_flush_method

    innodb_flush_method这个参数控制着innodb数据文件及redo log的打开.刷写模式,对于这个参数,文档上是这样描述的: 有三个值:fdatasync(默认),O_DSYNC,O ...

  4. HTML5——localStorage

    html5的学习,忘记的差不多了,特地拿出来重新记录一下,从它的本地存储开始吧! 假设这样的html结构: <div id= "one_storage" class=&quo ...

  5. java基础,集合,Arraylist,源码解析(基础)

    ArrayList 是什么,定义? 这是动态的数组,它提供了动态的增加和减少元素,实现了List接口(List实现Collection,所以也实现Collection接口)灵活的设置数组的大小等好处 ...

  6. HUST 1588 辗转数对

    1588 - 辗转数对 时间限制:1秒 内存限制:128兆 155 次提交 27 次通过 题目描述 假设当前有一个数对(a, b),我们可以通过一步将这个数对变为一个新数对(a + b, b)或者是( ...

  7. linux下如何删除文件夹?

    直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字-r 就是向下递归,不管有多少级目录,一并删除:-f 就是直接强行删除,不作任何提示的意思. 例如:删除文件夹实例: rm -rf ...

  8. Django 用散列隐藏数据库中主键ID

    最近看到了一篇讲Django性能测试和优化的文章, 文中除了提到了很多有用的优化方法, 演示程序的数据库模型写法我觉得也很值得参考, 在这单独记录下. 原文的演示代码有些问题, 我改进了下, 这里可以 ...

  9. 《图解http》知识点笔记

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica } p.p2 { margin: 0.0px 0.0px 0.0px 0. ...

  10. POJ 3829 Seat taking up is tough(——只是题目很长的模拟)

    题目链接: http://poj.org/problem?id=3829 题意描述: 输入矩阵的大小n和m,以及来占位置的人数k 输入n*m的教室座位矩阵,每个值表示该座位的满意度 输入每个人来占位置 ...