bis*_*rot 0 java functional-programming lazy-evaluation java-8 java-stream
我正在做一些Java 8流的"代数",也就是说,我正在尝试编写一个简单的操作Op,它将两个流作为输入并产生另一个流.
所以我有这个简单的代码,其目的是在一系列数字中打印secund最高值:
import java.util.Arrays;
import java.util.stream.IntStream;
public class SecundHighestValue {
public static void main(String[] args) {
//setting the input parameters
int [] numbers = {1, 2, 3, 4, 3, 4, 2, 1};
IntStream S1 = Arrays.stream(numbers);
IntStream S2 = Arrays.stream(new int[] {Arrays.stream(numbers).max().getAsInt()} );
// setting the operation
IntStream S3 = S1.filter(x-> x != S2.toArray()[0]); // doesn't work
/*** does work ***
int maxNumber = S2.toArray()[0];
IntStream S3 = S1.filter(x-> x != maxNumber);
*/
// accessing the operation's result stream S3
int secundMaxNumber = S3.max().getAsInt();
System.out.println("the secund highest value in the serie " +
Arrays.toString(numbers) + " is " + secundMaxNumber);
}
}
Run Code Online (Sandbox Code Playgroud)
除非我以这种方式拆分单行操作,否则此程序将无法运行:
int maxNumber = S2.toArray()[0];
IntStream S3 = S1.filter(x-> x != maxNumber);
Run Code Online (Sandbox Code Playgroud)
将操作保持在一行将引发此异常:
线程"main"中的异常java.lang.IllegalStateException:stream已被操作或关闭...
我知道它与filter()方法固有的懒惰有关.该API说明:
流操作分为中间(流生成)操作和终端(生成价值或副作用)操作.中间操作总是很懒惰.
实际上,堆栈跟踪显示在我尝试在下一行中访问其结果之前,操作不会执行.
这种行为在java8中是否有缺陷?这是一个错误吗?最重要的是,如何将操作保持在一行并使其工作?
如果可以通过源进行流式传输并且不是很昂贵,就像使用数组一样,您可能只需要流式传输两次,就像在azro的答案中一样:
int maxNumber = Arrays.stream(numbers).max().getAsInt();
int secondMaxNumber = Arrays.stream(numbers).filter(x-> x != maxNumber).max().getAsInt();
Run Code Online (Sandbox Code Playgroud)
如果流式传输两次不可能或不昂贵,您需要一个自定义收集器来有效地获得第二大值,即只保留必要的两个值.例如
final class SecondMax {
long max=Long.MIN_VALUE, semi=max;
void add(int next) {
if(next>semi) {
if(next>max) {
semi=max;
max=next;
}
else if(next<max) {
semi=next;
}
}
}
void merge(SecondMax other) {
if(other.max>Long.MIN_VALUE) {
add((int)other.max);
if(other.semi>Long.MIN_VALUE) add((int)other.semi);
}
}
OptionalInt get() {
return semi>Long.MIN_VALUE? OptionalInt.of((int)semi): OptionalInt.empty();
}
}
Run Code Online (Sandbox Code Playgroud)
使用此帮助程序,您可以在单个流操作中获取值:
OptionalInt secondMax = Arrays.stream(array)
.collect(SecondMax::new, SecondMax::add, SecondMax::merge).get();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
233 次 |
| 最近记录: |