Java Stream map 和 mapToObj 之间的区别

2022-08-31 17:30:49

我感觉不到Java 8 Streams中的方法之间的区别。在这两种情况下,我们都可以创建对象并将其返回到流中,那么为什么这些方法作为两个存在,而不仅仅是一个。map()mapToObj()

你能给我一个例子解释一下吗?


答案 1

你会看到这个很酷的模式。这些类包括 、 等。这样,您就可以在流操作中使用基元类型。因为否则,您必须使用 或 ,它将框住值。StreamIntStreamLongStreamDoubleStreamStream<Integer>Stream<Double>

同样,这些方法也这样做。在类中,有 方法,但在 类中情况略有不同。mapStream<T>mapToIntmapToDoubleIntStreamDoubleStream

在 中,该方法采用 一个 ,它将一个 int 映射到一个 int。如果要将流映射到 ,则必须使用 。 是一个好名字,因为它与映射到整数的区别。它表示流从 a 更改为 .之所以这样命名,与为什么这样命名的原因相同 - 表示类型/IntStreammapIntUnaryOperatorStream<T>mapToObjmapToObjmapIntStreamStream<T>mapToObjmapToIntStream


答案 2

数据类型的基元和对象版本(即 和 、 和 等)在Java中彼此之间并不真正兼容。它们通过自动装箱/拆箱的额外步骤实现兼容。因此,如果您有一个原始 int 流,并且您尝试使用 和 的对象版本(即 和 ),您将产生装箱和取消装箱元素的费用。intIntegerdoubleDoubleStreamFunctionStream<Integer>Function<Integer, Integer>

为了消除这个问题,函数包包含流的原始专用版本以及功能接口。例如,应使用 而不是 使用 。现在,您可以使用 处理流的每个元素。这将完全避免自动装箱/取消装箱。Stream<Integer>IntStreamIntFunction

因此,每当要处理基元元素流时,都应使用基元专用流(即 、、和)和基元专用功能接口(即 、、等)来实现更好的性能。IntStreamLongStreamDoubleStreamIntFunctionIntConsumerIntSupplier

还有一点需要注意的是,没有一个原始的专用功能接口(如 、 、 或 ) 扩展非原始功能接口(即 、 等)。IntFunctionDoubleFunctionIntConsumerFunctionConsumer

java.util.function package包含 、 和 (但不是 ) 所有功能接口的版本。例如,有一个、一个 DoubleFunction 和一个 ,它们是 函数 的 、 和 版本。这些函数与流的原始专用版本(如 、 和 )一起使用。intdoublelongfloatIntFunctionLongFunctionintdoublelongIntStreamDoubleStreamLongStream

让我们举几个例子:

Stream<Object> stream1 = Stream.of(1, 2, 3); //Will compile fine
IntStream intStream1 = IntStream.of(4, 5, 6); //Will compile fine

Stream<Object> stream2 = IntStream.of(4, 5, 6); //Does not compile
Stream<Object> stream3 = IntStream.of(4, 5, 6).mapToObj(e -> e); //mapToObj method is needed
IntStream intStream2 = Stream.of(4, 5, 6).mapToInt(e -> e); //mapToInt method is needed

总而言之,您可能使用的原因与 您可能使用的原因相同,即更改类型。mapToObjmapToIntStream


推荐