,值得你一看
Posted 李阿昀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了,值得你一看相关的知识,希望对你有一定的参考价值。
目录一览
闲扯一番
时间过得可真快啊,没想到今天就是除夕了,既然是除夕,那就该说点祝福的话语,喜庆喜庆,在这里我就祝大家在新的一年乐乐呵呵地把钱挣进口袋,身体健健康康,生活顺顺当当😊😊😊!
总想着在这最后一天应该做点什么有意义的事,于是就想干脆何不写一篇文章玩玩,于是这篇文章就在这样的背景下写出来了。另外,就是有读者私信催促我要继续更新文章,说到这,我不禁惭愧不已,离上一篇文章的更新已经差不多有27天了,快接近一个月了,怎能不教人汗颜,对此大家催促的对,我都不想说我自己了,只有寄希望于在春节给大家带来更多的文章来弥补了。
我这里还得说一点,有许多读者希望我更新「Spring Boot 2从入门到入坟」这一专栏中的文章,放心,我是一定会更完的,给大家吃一个定心丸,不会鸽哟😁!可能这篇更完之后,就更新专栏里面的文章,希望大家踊跃订阅,哈哈哈😊
回到主题,这篇文章的中心主旨是什么呢?相信大家从文章标题就能看出来,在这篇文章中我会给大家详细讲述一下强大的Stream API,这也是Java 8中两大最为重要的改变之一。
Stream是什么?
Java 8中有两大最为重要的改变。第一个是Lambda表达式;另外一个则是Stream API(位于java.util.stream.*
包下)。
Stream是Java 8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询,当然,也可以使用Stream API来并行执行操作。
简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。
那么Stream(翻译过来就是流)到底是什么呢?Stream(即流)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。大家一定要记住这句话,即集合讲的是数据,流讲的是计算!此外,我们还应尤其注意以下几点:
- Stream自己不会存储元素;
- Stream不会改变源对象,相反,它们会返回一个持有结果的新Stream;
- Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。
其实,只要是流,那么它们的概念几乎都是类似的,都是用于操作数据的,但是咱们现在遇到的这个流和IO流还是不一样的,这点大家一定要搞清楚。大家现在清楚了流是用来操作数据的,既然是来操作数据的,那是不是首先都得有一个数据源啊,大家觉得数据源是什么比较合适呢?根据上面的描述,你应该知道数据源既可以是集合,也可以是数组。说白了,我们现在可以对集合或者数组中的数据进行一些操作了。
那么能做一些什么操作呢?我给大家来娓娓道来吧!首先,流对数据源中的数据进行操作的时候,是不是说白了就是一个数据的传输啊!既然想完成数据传输,那么是不是得创建一个用于传输数据的管道啊!大家要注意,现在咱们遇到的这个流不一样的地方就是它在数据传输的过程中,可以做一系列流水线式的中间操作,比如过滤、筛选、切片等等。
做完这些中间操作以后,大家要切记的是原来的数据源并不会发生任何改变,取而代之的是,它会产生一个新流。如果要用一个图来形象地描述Stream(即流),那么可能会是下面这样子的。
这就有点类似于文件的复制,把源文件复制成另外一个文件时,源文件是不是不能变啊!
Stream使用的三个步骤
Stream使用的三个步骤如下:
- 创建Stream:一个数据源(例如集合、数组),获取一个流。说白了,就是首先得把数据源转换成流。
- 调用Stream的中间操作:一个中间操作链,对数据源的数据进行处理,有过滤、筛选以及切片等操作。
- 终止操作(或者终端操作):一旦执行终止操作,就执行中间操作链,并产生结果,后面的就不会再被使用了。
如果要用一个图来形象地描述Stream操作的三个步骤,那么可能会是下面这样子的。
不知大家能看得懂嘛?
如何创建Stream?
了解完Stream使用的三个步骤之后,我们先来看一下第一步,即如何创建Stream。
实际上,创建Stream(即流)一共有四种方式,下面我将会给大家一一来介绍。
通过Collection接口创建
通过Collection系列集合提供的stream方法或者parallelStream方法获取流对象。
Java 8中的Collection接口被扩展了,给我们提供了两个获取流的方法。第一个方法是stream,如下所示。
default Stream<E> stream()
return StreamSupport.stream(spliterator(), false);
注意,使用该方法获取的是串行流。
第二个方法是parallelStream,如下所示。
default Stream<E> parallelStream()
return StreamSupport.stream(spliterator(), true);
注意,使用该方法获取的是并行流。至于什么是并行流,咱们后面再说。
例如,以下代码就是通过这种方式来创建流的。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
拿到流之后,我们就可以做一系列流水线式的中间操作,并在最后生成结果了。
通过数组创建
我们还可以通过Java 8中的Arrays类的stream静态方法获取数组流哟!
public static <T> Stream<T> stream(T[] array)
return stream(array, 0, array.length);
而且Arrays类中还有许多重载的stream方法可以返回不同基本数据类型数组的Steam对象。
public static IntStream stream(int[] array)
return stream(array, 0, array.length);
public static LongStream stream(long[] array)
return stream(array, 0, array.length);
public static DoubleStream stream(double[] array)
return stream(array, 0, array.length);
从上可以知道,任何对象的数组都能转换成流。
例如,以下代码就是通过这种方式来获取数组流的。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
// 2. 通过Arrays类中的stream静态方法获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
通过Stream类中的of静态方法创建
可以使用Stream类中的of静态方法,通过显示值来创建一个流,该方法可以接收任意数量的参数。
@SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) // 接收一个或多个现有的值来创建一个流
return Arrays.stream(values);
例如,以下代码就是通过这种方式来获取流的。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
// 2. 通过Arrays类中的stream静态方法获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通过Stream类中的of静态方法获取流对象
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
通过静态方法Stream.iterate()
或者Stream.generate()
创建无限流
可以使用静态方法Stream.iterate()
或者Stream.generate()
来创建无限流。
创建无限流也有两种方式,一种是通过迭代来创建,即使用Stream类中的iterate静态方法来创建。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
// 2. 通过Arrays类中的stream静态方法获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通过Stream类中的of静态方法获取流对象
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 4. 创建无限流
/*
* 迭代(第一种创建无限流的方式)
*
* 第一个参数是种子,种子说白了就是一个起始值;
* 第二个参数是一个一元运算的操作,即Lambda表达式
*/
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
注意,现在单纯的有流呢,是没有任何效果的,只有做了中间操作和终止操作以后才会有效果。为了给大家好好看一下效果,我来个终止操作,如下所示。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
// 2. 通过Arrays类中的stream静态方法获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通过Stream类中的of静态方法获取流对象
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 4. 创建无限流
/*
* 迭代(第一种创建无限流的方式)
*
* 第一个参数是种子,种子说白了就是一个起始值;
* 第二个参数是一个一元运算的操作,即Lambda表达式
*/
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
// 要想看看这个无限流中到底有什么东西,那就得来个终止操作
stream4.forEach(System.out::println);
能看懂我写的什么吧!此时,运行以上test1测试方法,大家就会看到创建出来的无限流,如下图所示。
可以清楚地看到,从0这个种子开始+2的操作,是不是就会产生上面这一堆的偶数啊!这就是产生了一个无限流,并且是按照一元运算的规律产生了一个无限流,当然,这也称为迭代。
以上test1测试方法运行时,如果你不按下停止键,那么程序是停不下来的,也就是说会一直产生偶数。但是,有的时候我们并不需要这么多数,而只想要前十个数,那么该怎么办呢?这时,我们就可以来个中间操作了。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
// 2. 通过Arrays类中的stream静态方法获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通过Stream类中的of静态方法获取流对象
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 4. 创建无限流
/*
* 迭代(第一种创建无限流的方式)
*
* 第一个参数是种子,种子说白了就是一个起始值;
* 第二个参数是一个一元运算的操作,即Lambda表达式
*/
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
// 要想看看这个无限流中到底有什么东西,那就得来个终止操作
// stream4.forEach(System.out::println);
stream4.limit(10).forEach(System.out::println);
此时,运行以上test1测试方法,创建出来的无限流就是下面这样子的了,是不只会产生10个偶数啊!
知道第一种创建无限流的方式之后,接下来我们再来看一下创建无限流的第二种方式,即通过生成来创建,也就是使用Stream类中的generate静态方法来创建。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤:
*
* 1. 创建Stream
*
* 2. 中间操作
*
* 3. 终止操作(终端操作)
*
* @author liayun
* @create 2022-01-21 7:42
*/
public class TestStreamAPI1
// 创建Stream
@Test
public void test1()
// 1. 可以通过Collection系列集合提供的stream或parallelStream方法获取流对象
List<String> list = new ArrayList<>();
// 流也可以带泛型哟!
Stream<String> stream1 = list.stream();
// 2. 通过Arrays类中的stream静态方法获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
// 3. 通过Stream类中的of静态方法获取流对象
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 4. 创建无限流
/*
* 迭代(第一种创建无限流的方式)
*
* 第一个参数是种子,种子说白了就是一个起始值;
* 第二个参数是一个一元运算的操作,即Lambda表达式
*/
/*
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
// 要想看看这个无限流中到底有什么东西,那就得来个终止操作
// stream4.forEach(System.out::println);
stream4.limit(10).forEach(System.out::println);
*/
/*
* 生成(第二种创建无限流的方式)
*
* 例如,产生大量随机double数(0.0 <= x < 1.0)
*/
Stream.generate(() -> Math.random())
.forEach(System.out::println);
此时,运行以上test1测试方法,大家有可能会看到创建出来的如下无限流哟!
上面是不是产生了一个无限流啊,即会无限产生随机double数。
同理,有的时候我们是不并不需要这么多数啊,而只想要前五个数,那么这时该怎么办呢?很简单嘛,直接来个中间操作就行了。
package com.meimeixia.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.以上是关于,值得你一看的主要内容,如果未能解决你的问题,请参考以下文章