将流收集到Java不可变集合中

将流收集到Java不可变集合中

Java 8中引入了流(Streams)和收集器(Collectors)的概念。流是一系列对象的序列,我们从输入源(如数组、列表等)生成流,并支持聚合操作,例如筛选、映射、限制、缩减等。我们使用流将数据进行管道传输,并最终将其收集到某种形式的收集器中。收集器是存储流处理结果的容器,收集器可以是列表、映射或集合。

不可变集合是一种创建后无法更改其值的集合。我们需要不可变集合,因为许多时候我们可以拥有不会改变的数据集合,比如一年中的月份列表或一周中的天数等。使这些数据不可变(即数据不可改变)使得它们更加内存和空间高效。它们也是固有的线程安全的。总的来说,不可变对象需要比它们的可变对应对象占用更少的内存。

当我们构造一个对象后,如果它的状态不会改变,则将该对象视为不可变的。在创建一个不可变的集合实例之后,只要存在对它的引用,它就会始终保留相同的数据。

方法: 根据Java版本的不同,可以使用各种方法创建不可变对象的方法。

  1. Java 10之前
    • 使用”collectingAndThen”将流收集到不可修改的结构中
    • 谷歌的Guava库
  2. Java 10之后

  • toUnmodifiableList()
  • toUnmodifiableMap()
  • toUnmodifiableSet()

场景1: Java 10之前

方法1: 将流收集到不可修改的结构。在Java 10之前,Java中没有直接的方法来创建不可变集合。一种方法是创建一个流,并使用”collectingAndThen”方法将其收集到一个不可修改的结构中。

示例:

// Java程序演示将流收集到不可变集合中
// Pre java 10
// 使用collectingAndThen方法

// 从java.util package导入Collections、Collectors和Stream类
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;

// 主类
// PreJava10ImmutableCollections
public class GFG {

    // 主函数
    public static void main(String[] args) {

        // 创建带有整数元素的自定义输入列表
        var unmodifiableList
            = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
                    .collect(Collectors.collectingAndThen(
                        Collectors.toList(),
                        Collections::unmodifiableList));

        System.out.println(unmodifiableList);

        // 对此类操作将导致异常
        unmodifiableList.add(12);
    }
}

输出:

将流收集到Java不可变集合中

方法2: 使用谷歌的Guava库。为此,需要先将JAR文件包括在内。Guava库的JAR文件是下载JAR文件并在eclipse中将其添加到构建路径中。Guava库提供了ImmutableList类。下面是一个例子。

示例:

// Java程序来说明把流集合为不可变集合
// Java 10之前使用Google的Guava库
 
// 导入Guava库
import com.google.common.collect.ImmutableList;
// 从java.util包中导入类
import java.util.List;
import java.util.stream.IntStream;
 
// 主类
public class PreJava10ImmutableCollections {
 
    // 主方法
    public static void main(String[] args) {
 
        // 使用Guava库
        List<Integer> someList
            = IntStream.range(0, 15).boxed().collect(
                  ImmutableList.toImmutableList());
 
        // 打印和显示元素
        System.out.println(someList);
    }
}

输出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

注意: 我们也可以实现我们自己的不变列表、映射或集合版本。

场景2:Java 10及以上版本

Java 10引入了通过Collectors类创建不可变集合的函数。我们有三种方法,一种用于List,一种用于Set,一种用于Map。

方法1: 使用 toUnmodifiableList() 方法。假设我们有一个包含50个偶数的流,并从中创建一个不变的列表。

示例:

// Java程序来说明把流集合为不可变集合
// Java 10之后
// 使用toUnmodifiableList()方法
 
// 从java.util包中导入类
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
// 主类
public class GFG {
 
    // 主方法
    public static void main(String[] args)
    {
        // 创建一个整数类型的Stream类对象
        Stream<Integer> evenNumberStream
            = Stream.iterate(0, i -> i + 2).limit(50);
 
        // 创建一个整数类型的List类对象
        List<Integer> evenNumbers
            = (List<Integer>)evenNumberStream.collect(
                Collectors.toUnmodifiableList());
 
        // 打印列表中的所有元素
        System.out.println(evenNumbers);
 
        // 这些将会导致java.lang.UnsupportedOperationException
 
        evenNumbers.add(90);
        // evenNumbers.remove(1);
    }
}

输出:

将流收集到Java不可变集合中

方法2: 使用toUnmodifiableMap()方法

考虑一个Books类的示例。Books对象有两个参数,即‘Id’和‘Name’。我们将生成一个book对象的流。假设我们需要从这个对象的collection中生成一个不可变的Map。为此,我们使用toUnmodifiableMap()函数。

示例:

// Java程序演示如何将流收集到
// 不可变集合中
// Java 10以上版本
// 使用toUnmodifiableMap()方法
 
// 导入所需库
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
// 主类
// ImmutableCollectionMap
public class GFG {
 
    // 主方法
    public static void main(String[] args)
    {
 
        // 通过books类型的List类对象创建一本书流,并将其转换为Map类对象
        List<Books> libInventory = new ArrayList<Books>();
 
        // 上面创建对象后,添加元素
        // 自定义输入
        libInventory.add(
            new Books(1, "傲慢与偏见"));
        libInventory.add(new Books(2, "四签名"));
        libInventory.add(
            new Books(3, "理智与感性"));
        libInventory.add(new Books(4, "曼斯菲尔德公园"));
        libInventory.add(
            new Books(5, "马特雷斯圈"));
        libInventory.add(
            new Books(6, "巴斯克维尔的猎犬"));
        libInventory.add(new Books(7, "晚安月亮"));
        libInventory.add(new Books(
            8, "离我的生日还有多少天"));
        libInventory.add(
            new Books(9, "神秘身份"));
        libInventory.add(new Books(10, "谋杀谁谁"));
        libInventory.add(new Books(
            11, "赫克特·波洛的冒险"));
        libInventory.add(
            new Books(12, "冰与火之歌"));
 
        // 创建Map类对象
        // 声明类型为Integer和String的对象
        Map<Integer, String> unmutableInventory
            = libInventory.stream().collect(
                Collectors.toUnmodifiableMap(
                    Books::getBookNumber,
                    Books::getBookName));
 
        // 输出Map对象中的所有元素
        System.out.println(unmutableInventory);
 
        // 这将引发异常
        unmutableInventory.put(13, "某本书");
    }
}

输出:

将流收集到Java不可变集合中

方法 3: 使用toUnmodifiableSet()方法

实现: 通过流创建不可变集合,我们可以使用toUnmodifiableSet()函数。

// Java程序演示如何将流收集到
// 不可变集合中
// Java 10以上版本
// 使用toUnmodifiableSet()方法
 
// 导入所需库
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
// 主类
// ImmutableCollectionSet
public class GFG {
 
    // 主方法
    public static void main(String[] args)
    {
        // 创建类型为Double的流对象
        Stream<Double> randomDecimals
            = Stream.generate(Math::random).limit(30);
 
        // 现在创建类型为Double的Set类对象
        Set<Double> randomSet = randomDecimals.collect(
            Collectors.toUnmodifiableSet());
 
        // 输出Set对象中的元素
        System.out.println(randomSet);
 
        // 这将引发异常
        randomSet.add(100.0);
    }
}

将流收集到Java不可变集合中

结论: 这里我们看到了如何在Java中创建不可变集合。我们还看到了基于使用的Java版本创建集合的不同方法。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程