使用 IntStream 进行范围和循环





5.00/5 (1投票)
使用 IntStream 进行范围和循环。
在之前的文章中,我们学习了如何获取容器,将其内容流式传输到管道中,并研究了该管道中数据的几种不同操作(forEach
、map
、filter
、peek
)。
Java 8 支持几种专用流,其中管道包含特定类型的对象。今天,我们将学习IntStream
,它在管道中传递整数。
public class IntStreamExample
{
public static void main(String[] args)
{
System.out.println("[1,5]");
IntStream.rangeClosed(1, 5).forEach(System.out::println);
System.out.println("[1,5)");
IntStream.range(1, 5).forEach(System.out::println);
System.out.println("Just 3");
IntStream.of(3).forEach(System.out::println);
System.out.println("Specific values");
IntStream.of(1, 3, 5, 6).forEach
(System.out::println);
System.out.println("[1,3] and [4,6] joined");
IntStream.concat(IntStream.rangeClosed(1, 3),
IntStream.rangeClosed(4, 6)).forEach(System.out::println);
}
}
要构建我们的流,我们使用IntStream
类并使用其一个static
方法。上面的示例演示了其中一些方法。
对于错过之前文章的读者,::
运算符表示传递右侧的函数,并使用左侧的对象进行调用。
让我们描述每种方法
IntStream.rangeClosed(1, 5).map(x -> 6-x)
.forEach(System.out::println);
这有点笨拙(希望很快会添加一个逐步版本),但它确实有效。如果我们经常需要步长,我们可以基于IntStream
类创建自己的步长。
range
和rangeClosed
方法生成一个流,该流具有一个有序的整数管道,从第一个数字开始,到第二个数字结束。区别在于rangeClosed
包含终点,而我们的范围不包含。目前还没有带步长或递减值的版本——如果起始值超过最后一个元素,则管道将初始化为空。如果我们想要一个步长,我们使用map进行转换。of
方法将一个或多个值放入管道中。多值版本接受可变数量的int
(这意味着我们也可以传递一个int
数组)。- 最后,
concat
方法可以用于将两个或多个IntStream
组合成单个IntStream
。
请注意,还有一个empty()
方法,它会生成一个空流。
range
的一个用法是函数式for
循环。它是函数式的,因为它没有可变的循环变量。上面的示例已经演示了这一点——循环的“主体”只是打印了循环计数器。
如果我们想要嵌套两个循环呢?这很容易
public class Multiplication
{
public static void main(String[] args)
{
IntStream.rangeClosed(1, 10)
.forEach(i -> IntStream.rangeClosed(1, 10)
.forEach(
j -> System.out.println(i + " * " + j + " = " + i * j)));
}
}
通过使用forEach
操作,我们可以将每个元素映射到另一个流。我们不必立即使用该元素,我们可以在管道的后面使用它。在这个例子中,我们使用两个流来生成乘法表。
我们还可以将IntStream
的输出保存到数组中,如下所示
int[] a = IntStream.rangeClosed(1, 10).toArray();
这为我们提供了一种非常方便的方法来将数组初始化为一系列整数。
管道操作toArray
返回一个int[]
。如果我们想从两个或多个嵌套循环创建数组呢?我们在嵌套版本中遇到的问题是,我们不能在内循环中使用toArray()
,因为内循环是map
函数的一部分,而该函数期望的是int
而不是int[]
。这意味着我们必须使用另一个技巧
int[] a = IntStream.rangeClosed(1, 10)
.flatMap(i -> IntStream.rangeClosed(1, 10)
.map(j -> i * j))
.toArray();
在这里,我们使用flatMap
。flatMap
将多个IntStream
(这里有 10 个)展平为管道元素(int
)。然后将其传递给下一个操作,即toArray()
。
传递给flatMap
的 lambda 表达式被转换为IntFunction
,其apply
函数接受一个int
并返回一个IntStream
。这是一个显式实现它的内部类
private static class MultiplicationTable implements
IntFunction<IntStream>
{
@Override
public IntStream apply(int value)
{
return IntStream.rangeClosed(1, 10).map(j -> value * j);
}
}
使用调用
int[] a = IntStream.rangeClosed(1, 10)
.flatMap(new MultiplicationTable())
.toArray();
最后,这是一个使用局部函数的版本
public class Multiplication
{
private IntStream getTable(int i)
{
return IntStream.rangeClosed(1, 10).map(j -> i * j);
}
public void test()
{
int[] a = IntStream.rangeClosed(1, 10).flatMap
(this::getTable)
.toArray();
Arrays.stream(a).forEach(System.out::println);
}
public static void main(String[] args)
{
new Multiplication().test();
}
}
请注意,我们还使用了Arrays辅助类上的stream
函数来打印数组。为此,我们需要将数组传递到stream
函数中,然后我们可以使用forEach
进行打印。
这应该可以帮助你入门使用IntStream
。请注意,还有Long
和Double
的专用流,你可能也需要看看。
修订历史
- 2014年7月2日 -更正了类别