流的操作

流的使用一般包括三件事:

一个数据源来执行一个查询;

一个中间操作链,形成一条流的流水线;

一个终端操作,执行流水线,并能生成结果

中间操作

操作 类型 返回类型 操作参数 函数描述符
filter 中间 Stream Predicate T -> boolean
map 中间 Stream Function<T,R> T->R
limit 中间 Stream
sorted 中间 Stream Comparator (T,T)->int
distinct 中间 Stream

终端操作

操作 类型 目的
forEach 终端 消费流中的每个元素并对其应用Lambda.这一操作返回void
count 终端 返回流中元素的个数,这一操作返回long
collect 终端 把流归约成一个集合,比如List,Map甚至是Integer

使用流

筛选

出了filter ,流还支持一个叫做distinct的方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流.例如,如下代码会筛选出列表中所有的偶数,并确保没有重复

List<Integer> numbers = Arrays.asList(1,2,1,3,3,2,4);
numbers.stream()
.filter(i -> i%2 ==0)
.distinct()
.forEach(System.out::println);

截断流

流支持limit(n) 方法,该方法会返回一个不超过给定长度的流.

List<Dish> dishes = menu.stream()
.filter(d->d.getCalories()>300)
.limit(3)
.collect(toList());

跳过元素

流还支持skip(n)方法,返回一个扔掉了前n个元素的流.

List<Dish> dishes = menu.stream().filter(d->d.getCalories()>300).skip(2).collect(toList());

映射

对流中每一个元素应用函数

例如: 如果要找出每道菜的名称有多长,则如下:

List<Integer> dishNameLengths = menu.stream().map(Dish::getname).map(String::length).collect(toList())

流的扁平化

例如:给定单词列表["hello","world"],你想要返回列表["h","e","l","l","o","w","o","r","l","d"]

利用上面的可能是:

words.stream().map(word->word.split("")).distinct().collect(toList());

这个方法的问题自傲与,传递给map方法的Lambda为每个单词返回一个String[] (String列表),因此,map返回的流实际上是Stream< String[] >类型的.你真正想要的是用Stream< String > 来表示一个字符流

1.尝试使用map和Arrays.stream()

String[] arrayOfWords = {"GoodBye","World"};
Stream< String> streamOfWords = Arrays.stream(arrayOfWords);

2.使用flatMap

        String[] arrayOfWords = {"GoodBye","World"};
Stream< String> streamOfWords = Arrays.stream(arrayOfWords);
List<String[]> collect = streamOfWords.map(m -> m.split("")).collect(toList());
System.out.println(collect);

例2:

给定列表[1,2,3] 和[3,4] ,返回[(1,3),(1,4),(2,3).....]

        List<Integer> integers = Arrays.asList(1, 2, 3);
List<Integer> integers1 = Arrays.asList(3, 4);
List<int[]> collect = integers.stream()
.flatMap(i -> integers1.stream()
.map(j -> new int[]{i, j}))
.collect(toList());
collect.forEach(i -> {
String s = Arrays.toString(i);
System.out.println(s);
});

例3:

扩展前面的例子,只返回综合能被3正处的数对呢?

        List<Integer> int1 = Arrays.asList(1, 2, 3);
List<Integer> int2 = Arrays.asList(3, 4);
List<int[]> collect = int1.stream().flatMap(i -> int2.stream().filter(j -> (i + j) % 3 == 0).map(j -> new int[]{i, j})).collect(toList());
System.out.println(collect);

查找和匹配

匹配
1.检查谓词是否至少匹配一个一元素

anyMatch方法可以回答"流中是否有一个元素能匹配给定的谓词"

if(menu.stream().anyMatch(Dish::isVegetarian)){
System.out.println("The menu is vegetarian friendly!!");
}
2.检查谓词是否匹配所有元素

例如:用allMatch来看看菜品是否有利健康

boolean isHealthy = menu.stream().allMatch(d->d.getCalories()<1000);
3.确保流中没有任何元素与给定的谓词匹配 noneMatch
boolean isHealthy = menu.stream().noneMatch(d->d.getCalories()<1000);
查找
findAny方法将返回当前流中的任意元素
Optional<Dish> dish = menu.stream().filter(Dish::isVegetarian).findAny();
查找第一个元素
List<Integer> someNumbers = Arrays.asList(1,2,3,4,5);
Optional<Integer> firstSquareDivisibleByThree =
someNumbers.stream()
.map(x->x*x)
.filter(x->x%3 == 0)
.findFirst();

归约

元素求和 reduce

reduce接受两个参数

一个初始值,这里是0

一个BinaryOperator< T >来将两个元素结合起来产生一个新值 ,这里我们用的是lambda(a,b)->a+b;

int sum = numbers.stream().reduce(0,(a,b)->a+b);

相乘:

int product = numbers.stream().reduce(1,(a,b)->a*b);

在java 8 中,Integer类现有了一个静态的sum方法来对两个数求和

int num=numbers.stream().reduce(0,Integer::sum);

最大值:

Optional<Integer> max = numbers.stream().reduce(Intger::max)

最小值:

Optional<Integer> min = numbers.stream().reduce(Integer::min);

数值流

原始类型流特化

java 8 引入了三个原始类型特化流接口来专门支持处理数值流的方法:IntStream . DoubleStream 和LongStream,.

分别将流中的元素特化成为int,long ,double,从而避免了暗含装箱成本

1.映射到数值流

将流转化为特化版本的常用方法是mapToInt,mapToDouble ,mapToLong.

int calaories = menu.stream()
.mapToInt(Dish::getCalories)//返回一个IntStream
.sum();

2.转换回対向流 boxed

IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();

3.默认值OptionalInt

IntStream中有个默认值0,所以,为了解决求最大值或最小值的问题 ,使用Optional原始类型特化版本:OptionalInt,

OptionalDouble,OptionalLong.

例如:要找到IntStream中的最大元素,可以调用max方法,它会返回一个OptionalInt:

OptionalInt maxCalories = menu.stream()
.mapToInt(Dish::getCalories)
.max();
//如果没有最大值的话,可默认一个最大值
int max = maxCalories.orElse(1);

4.数值范围

假如你想要生成1到100之间的所有数字. java8引入了两个可以用于IntStream和LongStream的静态方法,帮助生成这种范围:range和rangeClosed. 这两个方法都是第一个参数接受起始值,第二个参数接受结束值.但是range是不包含结束值的,而rangeClosed则包含结束值

IntStream evenNumbers = IntStream.rangeClosed(1,100)
.filter(n -> n % 2 == 0);//一个从1到100的偶数流 System.out.println(evenNumbers.count());//从1到100有50个偶数

构建流

由值创建流

可以使用静态方法Stream.of,通过显示值创建一个流.它可以接受任意数量的参数

Strean<String> stream = Stream.of("java 8","Lambdas ","In ","Action");
stream.map(String::toUpperCase).forEach(System.out::println);
//使用empty得到一个空流
Stream<String> emptySteam = Stream.empty();
由数组创建流
int[] numbers = {2,3,4,11,13};
int sum = Arrays.stream(numbers).sum();
由文件生成流
long uniqueWords = 0;
try(Stream<String> lines =
Files.lines(Paths.get("data.txt"),Charset.defaultCharset())){
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
.distinct()
.count();
}catch(IOException e){ }
由函数生成流:创建无限流

Stream.iterate和Stream.generate ,一般来说应该使用limit(n)来对这种流加以限制,以避免打印无穷多个值

1.迭代

Stream.iterate(0,n -> n+2)
.limit(10)
.forEach(System.out::println);

2.生成

与iterate方法类似,generate方法也可生成一个无限流.但generate不是依次对每个新生成的值应用函数的.它接受一个Supplier< T >类型的Lambda提供新的值

Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
//下面的代码就是出安静了一个斐波那契
IntSupplier fib = new IntSuppleir(){
private int previous = 0;
private int current = 1;
public int getAsint(){
int oldPrevious = this.previous;
int nextValue = this.previous + this.current;
this.previous = this.current;
this.current = nextValue;
return oldPrevious;
}
};
IntStream.generate(fib).limit(10).forEach(System.out::println);

java8-流的操作的更多相关文章

  1. Java8中的Stream流式操作 - 入门篇

    作者:汤圆 个人博客:javalover.cc 前言 之前总是朋友朋友的叫,感觉有套近乎的嫌疑,所以后面还是给大家改个称呼吧 因为大家是来看东西的,所以暂且叫做官人吧(灵感来自于民间流传的四大名著之一 ...

  2. 《JAVA8开发指南》使用流式操作

    为什么需要流式操作 集合API是Java API中最重要的部分.基本上每一个java程序都离不开集合.尽管很重要,但是现有的集合处理在很多方面都无法满足需要. 一个原因是,许多其他的语言或者类库以声明 ...

  3. Java8——Stream流式操作的一点小总结

    我发现,自从我学了Stream流式操作之后,工作中使用到的频率还是挺高的,因为stream配合着lambda表达式或者双冒号(::)使用真的是优雅到了极致!今天就简单分(搬)享(运)一下我对strea ...

  4. Java8 流式 API(`java.util.stream`)

    熟悉 ES6 的开发者,肯定对数组的一些方法不是很陌生:map.filter 等.在对一组对象进行统一操作时,利用这些方法写出来的代码比常规的迭代代码更加的简练.在 C♯ 中,有 LINQ 来实现.那 ...

  5. 公子奇带你进入Java8流的世界(一)

    在说流之前,我们先来看看集合,为什么呢?作为Java8中的新成员,它和集合有很多相似之处,同时它们也是可以互相转化的.集合不仅仅是Java语言,任何一门高级开发语言都有集合的概念,集合顾名思义,就是很 ...

  6. 公子奇带你进入Java8流的世界(二)

    在上一篇中我们带领大家简单的了解流的概念及使用场景,本节我们就来好好的介绍流的常见用法. 一.筛选和切片 对于一串流,我们有时需要取出我们需要的流中某些元素,主要是通过谓词筛选.看代码: 首先定义一个 ...

  7. IO流(四)__流的操作规律总结

    流的操作规律: 1.明确源和目的 源:InputStream Reader 目的:OutputStream Writer 2.明确数据是否是纯文本数据 源:是纯文本:Reader 否:InputStr ...

  8. C# IO流的操作

    C# IO流的操作非常重要,我们读写文件都会使用到这个技术,这里先演示一个文件内容复制的例子,简要说明C#中的IO操作. namespace ConsoleApplication1 { class P ...

  9. Java---IO加强(3)-IO流的操作规律

    一般写关于操作文件的读取的几个通用步骤!!! 1.明确源和目的. 源:InputStream Reader 一定是被读取的. 目的:OutputStream Writer 一定是被写入的. 2.处理的 ...

  10. IO流的操作规律

    输入流和输出流相对于内存设备而言. 将外设中的数据读取到内存中:输入将内存的数写入到外设中:输出. 字符流的由来:其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表.获取对应的文字.在 ...

随机推荐

  1. Enum的简单扩展

    1 添加一个描述的Attribute public enum MessageResult { [System.ComponentModel.Description("未通过")] ...

  2. 苹果二代TWS无线耳机AirPods调研

    产品介绍 苹果AirPods二代自从2018年9月份上市以来,到现在将近一年的时间了,据江湖传闻,苹果AirPods的总售卖个数,已经超过了5000W部,这样价格的TWS耳机,能够卖那么多的量,估计也 ...

  3. 搭建minima主题的github博客网站

    layout: post title: "搭建minima主题的github博客网站" date: 2019-04-20 19:20:20 +0800 --- 作者:吴甜甜 个人博 ...

  4. 渐进式web应用开发---service worker (二)

    阅读目录 1. 创建第一个service worker 及环境搭建 2. 使用service worker 对请求拦截 3. 从web获取内容 4. 捕获离线请求 5. 创建html响应 6. 理解 ...

  5. windows container 踩坑记

    windows container 踩坑记 Intro 我们有一些服务是 dotnet framework 的,不能直接跑在 docker linux container 下面,最近一直在折腾把它部署 ...

  6. 单元测试jest部署

    引入jest需安装的基础插件: 基础插件 @babel/core 编译工具核心模块包 @babel/preset-env 编译工具,支持es2015特性的编译打包工具包 babel-jest 对.js ...

  7. Python 爬虫:豆瓣电影Top250,包括电影导演、类型、年份、主演

    结果输出到文本文件中. import codecs import requests from bs4 import BeautifulSoup headers={'User-Agent': 'Mozi ...

  8. [Spring-Cloud-Alibaba] Sentinel 整合RestTemplate & Feign

    Sentinel API Github : WIKI Sphu (指明要保护的资源名称) Tracer (指明调用来源,异常统计接口) ContextUtil(标示进入调用链入口) 流控规则(针对来源 ...

  9. 从0系统学Android--1.2 手把手带你搭建开发环境

    要想进行程序开发,首先我们需要搭建开发环境,下面就开始搭建环境. 1.2.1 所需的工具 首先 Android 开发是基于 Java 的,因此你需要掌握简单的 Java 语法.会基础的 Java 语法 ...

  10. Java零基础个人学习路线总结

    之前学习Java的时候走过一些弯路,一直想写一篇文章来总结下自己对自学Java的认识.趁着这次开通专栏的机会整理一篇文章,既可以巩固所学,也可以为后来境遇相同的人做个参考. 首先提出几个问题 Java ...