流的操作

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

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

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

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

中间操作

操作 类型 返回类型 操作参数 函数描述符
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. PATB 1018. 锤子剪刀布

    时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图 ...

  2. 逻辑、集合运算上的卷积一览(FMT、FWT,……)

    \oplus=\and,\or,\veebar 简介 对于逻辑\(\oplus\)的卷积,而且你不能N方豹草 \[ A_k=\sum_{i\oplus j=k} B_i\times C_k\\ \] ...

  3. 浅谈Invoke 和 BegionInvoke的用法

    很多人对Invoke和BeginInvoke理解不深刻,不知道该怎么应用,在这篇博文里将详细阐述Invoke和BeginInvoke的用法: 首先说下Invoke和BeginInvoke有两种用法: ...

  4. Java线程池原理浅析

    什么是线程池? 为了避免频繁重复的创建和销毁线程,我们可以让这些线程进行复用,在线程池中,总会有活跃的线程在占用,但是线程池中也会存在没有占用的线程,这些线程处于空闲状态,当有任务的时候会从池子里面拿 ...

  5. kuangbin专题 专题一 简单搜索 Fire Game FZU - 2150

    题目链接:https://vjudge.net/problem/FZU-2150 题意:’ . '代表火无法烧着的地方,‘ # ’表示草,火可以烧着.选择任意两个‘ # ’(可以两个都选同一个 ‘ # ...

  6. goroutine上下文切换机制

    goroutine是go语言的协程,go语言在语言和编译器层面提供对协程的支持.goroutine跟线程一个很大区别就是线程是操作系统的对象,而goroutine是应用层实现的线程.goroutine ...

  7. 1. 在Mac OS中配置CMake的详细图文教程

    CMake是一个比make更高级的跨平台的安装.编译.配置工具,可以用简单的语句来描述所有平台的安装(编译过程).并根据不同平台.不同的编译器,生成相应的Makefile或者project文件.本文主 ...

  8. 【Aizu - 0525】Osenbei (dfs)

    -->Osenbei 直接写中文了 Descriptions: 给出n行m列的0.1矩阵,每次操作可以将任意一行或一列反转,即这一行或一列中0变为1,1变为0.问通过任意多次这样的变换,最多可以 ...

  9. java字符串的替换replace、replaceAll、replaceFirst的区别

    看代码: String s = "my.test.txt"; System.out.println(s.replace(".", "#")) ...

  10. 洛谷P2790 ccj与zrz之积木问题 题解

    题目链接:https://www.luogu.org/problemnew/show/P2790 这题码量稍有点大... 分析: 这道题模拟即可.因为考虑到所有的操作vector可最快捷的实现,所以数 ...