Java8:使用 IntStream 作为自定义收集器的供应商参数
Java8: Using an IntStream as a Supplier parameter for custom Collector
对于流对象,是不是可以使用collect方法写一个自定义的Collector对象,收集到另一个流对象?我最近刚刚了解了流,并试图尽可能多地使用它们,我 运行 解决了这个问题。
我的代码是:
// method to return how many unique letters are used in
// the Strings in the given stream
public int uniqueLetters(Stream<String> stream){
// transfer Strings to an uppercase char stream
IntStream allLets = stream.collect(IntStream::empty,
(s1, s2) -> { String toAdd = s2.toUpperCase();
IntStream cs = toAdd.chars();
IntStream.concat(s1, cs); //exception thrown on this line
}, IntStream::concat);
// use distinct on char stream and count
return (int) allLets.distinct().count();
}
此代码编译并且 collect 方法对于流中的第一个 String 运行良好,但它第二次到达 IntStream.concat(s1, cs) 我得到以下异常:
java.lang.IllegalStateException: stream has already been operated upon or closed
我对此的解释是,一旦我的第一个 String 转换为 IntStream 并且 collect 方法移动到下一个 String,我的第一个 IntStream 就会关闭。那是对的吗?为什么会这样?
这是我为自己发明的练习,目的是尝试获得更多关于流和函数式编程的经验。我知道这可能不是编写此方法的最佳方式。我想知道为什么这不起作用,而不是我可以采取的其他方法。
通过调用 concat
,您不会改变 s1
。 concat
returns 串联流。流首先是不可变的。
这意味着您开始使用的 Stream.empty
从未改变,并且在 concat
方法中一次又一次地使用它。但是,您不能 在 concat
中使用流两次。这算作 "operate upon the stream"。所以当你第二次尝试这样做时,你得到了一个非法状态异常,如记录:
A stream should be operated on (invoking an intermediate or terminal
stream operation) only once. This rules out, for example, "forked"
streams, where the same source feeds two or more pipelines, or
multiple traversals of the same stream. A stream implementation may
throw IllegalStateException if it detects that the stream is being
reused. However, since some stream operations may return their
receiver rather than a new stream object, it may not be possible to
detect reuse in all cases.
为了解决您查找唯一字符的问题,您无需收集到流。只需这样做:
public static int uniqueLetters(Stream<String> stream){
return (int)stream.flatMapToInt(String::chars).distinct().count();
}
flatMap
可能是您试图通过收集到流来做的事情。现在你知道那叫 flatMap
.
对于流对象,是不是可以使用collect方法写一个自定义的Collector对象,收集到另一个流对象?我最近刚刚了解了流,并试图尽可能多地使用它们,我 运行 解决了这个问题。
我的代码是:
// method to return how many unique letters are used in
// the Strings in the given stream
public int uniqueLetters(Stream<String> stream){
// transfer Strings to an uppercase char stream
IntStream allLets = stream.collect(IntStream::empty,
(s1, s2) -> { String toAdd = s2.toUpperCase();
IntStream cs = toAdd.chars();
IntStream.concat(s1, cs); //exception thrown on this line
}, IntStream::concat);
// use distinct on char stream and count
return (int) allLets.distinct().count();
}
此代码编译并且 collect 方法对于流中的第一个 String 运行良好,但它第二次到达 IntStream.concat(s1, cs) 我得到以下异常:
java.lang.IllegalStateException: stream has already been operated upon or closed
我对此的解释是,一旦我的第一个 String 转换为 IntStream 并且 collect 方法移动到下一个 String,我的第一个 IntStream 就会关闭。那是对的吗?为什么会这样?
这是我为自己发明的练习,目的是尝试获得更多关于流和函数式编程的经验。我知道这可能不是编写此方法的最佳方式。我想知道为什么这不起作用,而不是我可以采取的其他方法。
通过调用 concat
,您不会改变 s1
。 concat
returns 串联流。流首先是不可变的。
这意味着您开始使用的 Stream.empty
从未改变,并且在 concat
方法中一次又一次地使用它。但是,您不能 在 concat
中使用流两次。这算作 "operate upon the stream"。所以当你第二次尝试这样做时,你得到了一个非法状态异常,如记录:
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream. A stream implementation may throw IllegalStateException if it detects that the stream is being reused. However, since some stream operations may return their receiver rather than a new stream object, it may not be possible to detect reuse in all cases.
为了解决您查找唯一字符的问题,您无需收集到流。只需这样做:
public static int uniqueLetters(Stream<String> stream){
return (int)stream.flatMapToInt(String::chars).distinct().count();
}
flatMap
可能是您试图通过收集到流来做的事情。现在你知道那叫 flatMap
.