各种stream类中的close()方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各种stream类中的close()方法相关的知识,希望对你有一定的参考价值。

请问一下 各种stream类中(FileStream、StreamWriter/Reader 等等的流操作)都有一个Close()的方法,这个方法应该在何时用呢??

俺看过MSDN 它的实例一般都把流操作放在Using块当中,有时候在操作最后不使用Close(),并且注释说Using块也可以关闭Stream

但是有些实例,它也使用Using块,但是在操作完毕时也照样使用Close()
比如下面两个例子:
例一:
// The using statement also closes the StreamWriter.
using (StreamWriter sw = new StreamWriter("TestFile.txt"))

// Add some text to the file.
sw.Write("This is the ");
sw.WriteLine("header for the file.");
sw.WriteLine("-------------------");
// Arbitrary objects can also be written to the file.
sw.Write("The date is: ");
sw.WriteLine(DateTime.Now);

这个Using块的最后它没有使用Close()
例二:
if (File.Exists(FILE_NAME))

Console.WriteLine("0 already exists.", FILE_NAME);
return;

using (StreamWriter sw = File.CreateText(FILE_NAME))

sw.WriteLine ("This is my file.");
sw.WriteLine ("I can write ints 0 or floats 1, and so on.",
1, 4.2);
sw.Close();

这一段,也用Using,在Using块最后却使用了Close();

到底Close()应该在什么时候使用呢???

希望各位前辈能给予解答 小弟在此先谢了

因为stream对象需要占用非托管资源(内存,系统I/O等),using是StreamWriter 使用完毕后释放StreamWriter使用的资源,当然也包括他的内部stream占用的资源。而close方法必须调用关闭流,因为可以保证文件完全写入。否则的话文件可能写入失败或者写入内容不全。 参考技术A 你不需要用它的时候就close
using(。。。。)这里创建的对象生存期在using语句块之内,出了这个语句块就会被GC
参考技术B 使用 using 的时候,可以不使用 close,但是使用也没关系,都可以

,值得你一看

目录一览

闲扯一番

时间过得可真快啊,没想到今天就是除夕了,既然是除夕,那就该说点祝福的话语,喜庆喜庆,在这里我就祝大家在新的一年乐乐呵呵地把钱挣进口袋,身体健健康康,生活顺顺当当😊😊😊!

总想着在这最后一天应该做点什么有意义的事,于是就想干脆何不写一篇文章玩玩,于是这篇文章就在这样的背景下写出来了。另外,就是有读者私信催促我要继续更新文章,说到这,我不禁惭愧不已,离上一篇文章的更新已经差不多有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(即流)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。大家一定要记住这句话,即集合讲的是数据,流讲的是计算!此外,我们还应尤其注意以下几点:

  1. Stream自己不会存储元素;
  2. Stream不会改变源对象,相反,它们会返回一个持有结果的新Stream;
  3. Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。

其实,只要是流,那么它们的概念几乎都是类似的,都是用于操作数据的,但是咱们现在遇到的这个流和IO流还是不一样的,这点大家一定要搞清楚。大家现在清楚了流是用来操作数据的,既然是来操作数据的,那是不是首先都得有一个数据源啊,大家觉得数据源是什么比较合适呢?根据上面的描述,你应该知道数据源既可以是集合,也可以是数组。说白了,我们现在可以对集合或者数组中的数据进行一些操作了。

那么能做一些什么操作呢?我给大家来娓娓道来吧!首先,流对数据源中的数据进行操作的时候,是不是说白了就是一个数据的传输啊!既然想完成数据传输,那么是不是得创建一个用于传输数据的管道啊!大家要注意,现在咱们遇到的这个流不一样的地方就是它在数据传输的过程中,可以做一系列流水线式的中间操作,比如过滤、筛选、切片等等。

做完这些中间操作以后,大家要切记的是原来的数据源并不会发生任何改变,取而代之的是,它会产生一个新流。如果要用一个图来形象地描述Stream(即流),那么可能会是下面这样子的。

这就有点类似于文件的复制,把源文件复制成另外一个文件时,源文件是不是不能变啊!

Stream使用的三个步骤

Stream使用的三个步骤如下:

  1. 创建Stream:一个数据源(例如集合、数组),获取一个流。说白了,就是首先得把数据源转换成流。
  2. 调用Stream的中间操作:一个中间操作链,对数据源的数据进行处理,有过滤、筛选以及切片等操作。
  3. 终止操作(或者终端操作):一旦执行终止操作,就执行中间操作链,并产生结果,后面的就不会再被使用了。

如果要用一个图来形象地描述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.以上是关于各种stream类中的close()方法的主要内容,如果未能解决你的问题,请参考以下文章

adodb.stream的关闭方法

错误mycat报错:close connection,reason:stream close ...

java使用stream对日期排序

jdk8-stream的api

停止使用 Stream 侦听器的消息

大数据量文本怎么通过adodb.stream逐行读取(VBS)