Java 把一个Stream收集到一个不可变的Collection中
Stream和Collection是在Java 8中引入的,引入了流的概念。一个流是一个序列,一个对象的序列。我们从数组、列表等输入源生成流,并支持过滤、映射、限制、减少等聚合操作。我们使用流来处理数据,最终将其收集到某种形式的收集器中。采集器只不过是用来存储流处理结果的容器。采集器可以是一个List、Map或Set。
一个不可变的集合是一个一旦创建就不能改变其值的集合。我们确实需要不可变的集合,因为很多时候我们可以有不改变的数据集合,即查找列表。例如,一年中的几个月或一周中的几天的列表,等等。让这样的列表(其中的数据不会改变)成为不可更改的,使它们更节省内存和空间。它们在本质上也是线程安全的。一般来说,不可变的对象需要的内存比可变的对象少得多。
如果一个对象在构建后其状态不能改变,则被认为是不可变的。在你创建了一个集合的不可变实例后,只要有对它的引用存在,它就会持有相同的数据。
方法: 根据Java版本的不同,有多种方法可用于创建不可更改的对象,随着Java版本的进步,我们可以用这些方法创建不可更改的集合。
- Java 10之前
- 创建流并使用 “collectingAndThen” 将其收集到一个不可修改的结构中。
- 谷歌的Guava库
- Java 10之后
- toUnmodifiableList()
- 解释为:toUnmodifiableMap()
- toUnmodifiableSet()
情景1:Java 10之前
方法1: 创建流并将其收集到一个不可修改的结构中。在Java 10之前,没有直接的方法可以在Java中创建一个不可变的集合。一种方法是创建一个Stream,并使用”collectingAndThen“方法将其收集到一个不可修改的结构中。
示例:
// Java Program to illustrate Collecting a Stream to an
// Immutable Collection
// Pre java 10
// Using collectingAndThen method
// Importing Collections, Collectors and Stream classes
// from java.util package
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// Main class
// PreJava10ImmutableCollections
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Custom inputs integer elements in List
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);
// Operations like this will result in an exception
unmodifiableList.add(12);
}
}
输出:
方法2: 使用谷歌的Guava库。为此,需要一个前提工作,那就是包含JAR文件。Guava库的JAR是下载jar并将其添加到eclipse的构建路径中。Guava库提供了ImmutableList类。下面是一个例子。
示例:
// Java Program to illustrate Collecting a
// Stream to an Immutable Collection
// Pre java 10 Using Google’s Guava library
// Importing Guava library
import com.google.common.collect.ImmutableList;
// Importing classes from java.util package
import java.util.List;
import java.util.stream.IntStream;
// Main class
public class PreJava10ImmutableCollections {
// main driver method
public static void main(String[] args) {
// Using the Guava Libraries
List<Integer> someList
= IntStream.range(0, 15).boxed().collect(
ImmutableList.toImmutableList());
// Print and display the elements
System.out.println(someList);
}
}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
注意: 我们也可以实现自己的版本来创建不可变的list、map或set。
情况2:Java版本10及以上
Java第10版通过Collectors类引入了创建Immutable集合的功能。我们有3个方法,一个用于List,一个用于Set,还有一个用于Map。
方法1: .假设我们有一个前50个偶数的流,并从中创建一个不可变的列表。
示例:
// Java Program to illustrate Collecting a Stream to
// an Immutable Collection
// Post java 10
// using toUnmodifiableList() method
// Importing classes from java.util package
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// Main Class
// ImmutableCollectionList
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating Stream class object of integer type
Stream<Integer> evenNumberStream
= Stream.iterate(0, i -> i + 2).limit(50);
// Creating List class object of integer type
List<Integer> evenNumbers
= (List<Integer>)evenNumberStream.collect(
Collectors.toUnmodifiableList());
// Print all elements in the List object
System.out.println(evenNumbers);
// These will result in
// java.lang.UnsupportedOperationException
evenNumbers.add(90);
// evenNumbers.remove(1);
}
}
输出:
方法2: 使用toUnmodifiableMap()方法
考虑一个书籍类的例子。图书对象有两个参数,即’Id’和’Name’。我们将生成一个书籍对象的流。假设我们必须从这个对象的集合中生成一个不可变的Map。要做到这一点,我们使用toUnmodifiableMap()函数。
示例:
// Java Program to illustrate Collecting a Stream to
// an Immutable Collection
// Post java 10
// Using toUnmodifiableMap() method
// Importing required libraries
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// Main Class
// ImmutableCollectionMap
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating a Map from a Stream of books by
// creating an object of List class of books type
List<Books> libInventory = new ArrayList<Books>();
// Adding elements to the above object created
// Custom input entries
libInventory.add(
new Books(1, "Pride and Prejudice"));
libInventory.add(new Books(2, "The Sign of Four"));
libInventory.add(
new Books(3, "Sense and Sensibility"));
libInventory.add(new Books(4, "Mansfield Park"));
libInventory.add(
new Books(5, "The Materese Circle"));
libInventory.add(
new Books(6, "The Hound of Baskerville"));
libInventory.add(new Books(7, "Goodnight Moon"));
libInventory.add(new Books(
8, "How many sleeps till my Birthday"));
libInventory.add(
new Books(9, "The Bourne Identity"));
libInventory.add(new Books(10, "Murder She Wrote"));
libInventory.add(new Books(
11, "The adventures of Hercule Poirot"));
libInventory.add(
new Books(12, "The song of Ice and Fire"));
// Creating a Map class object
// Declaring object of integer and string type
Map<Integer, String> unmutableInventory
= libInventory.stream().collect(
Collectors.toUnmodifiableMap(
Books::getBookNumber,
Books::getBookName));
// Print all the elements in the Map object created
// above
System.out.println(unmutableInventory);
// This will result in an Exception
unmutableInventory.put(13, "Some book");
}
}
输出:
方法3: 使用toUnmodifiableSet()方法
实施情况: 从一个流中创建一个不可修改的集合,要做到这一点,我们使用toUnmodifiableSet()函数。
// Java Program to illustrate Collecting a Stream to
// an Immutable Collection
// Post java 10
// Using toUnmodifiableSet() method
// Importing required libraries
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// Main class
// ImmutableCollectionSet
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating Stream object of type Double
Stream<Double> randomDecimals
= Stream.generate(Math::random).limit(30);
// Now creating Set class object of type Double
Set<Double> randomSet = randomDecimals.collect(
Collectors.toUnmodifiableSet());
// Print and display elements in Set object
System.out.println(randomSet);
// This will produce an exception
randomSet.add(100.0);
}
}
结论: 在这里,我们看到了如何在Java中从一个流中创建不可变的集合。我们还看到了根据所使用的Java版本,用来创建集合的不同方法。