08-案例实现
案例实现
根据如下步骤实现本案例。
1.首先,实现这个例子所需的一些辅助类。6.2节所用的 Person
和 PersonGenerator
类也将在本节中使用。
2.创建一个名为 DoubleGenerator
的类。实现 generateDoubleList()
方法来生成一个包含双精度型数字的列表。该方法接收两个参数,它们分别是列表的大小和最大值。它将生成一个包含随机双精度型数字的列表:
public class DoubleGenerator {
public static List<Double> generateDoubleList(int size,
int max) {
Random random=new Random();
List<Double> numbers=new ArrayList<>();
for (int i=0; i<size; i++) {
double value=random.nextDouble()*max;
numbers.add(value);
}
return numbers;
}
3.实现一个名为 generateStreamFromList()
的方法。该方法接收一个包含 double
数字的 List
作为参数,并利用列表元素生成一个 DoubleStream
流。出于这个原因,我们将用 DoubleStream.Builder
类来构造这个流:
public static DoubleStream generateStreamFromList(List<Double>
list) {
DoubleStream.Builder builder=DoubleStream.builder();
for (Double number : list) {
builder.add(number);
}
return builder.build();
}
4.创建 Point
类。该类内含两个双精度型属性( x
和 y
),以及它们的 get()
和 set()
方法。由于该类的代码非常简单,因此不再展示。
5.创建 PointGenerator
类,其中有一个名为 generatePointList()
的方法。该方法接收所要生成的列表的大小,并返回包含随机 Point
对象的列表:
public class PointGenerator {
public static List<Point> generatePointList (int size) {
List<Point> ret = new ArrayList<>();
Random randomGenerator=new Random();
for (int i=0; i<size; i++) {
Point point=new Point();
point.setX(randomGenerator.nextDouble());
point.setY(randomGenerator.nextDouble());
ret.add(point);
}
return ret;
}
}
6.现在创建一个包含 main()
方法的 Main
类。在 main()
方法中,我们用 Double- Generator
类创建一个包含10000个 double
型数值的列表:
public class Main {
public static void main(String args[]) {
List<Double> numbers = DoubleGenerator.generateDoubleList
(10000, 1000);
7. Stream
以及特殊的 DoubleStream
、 IntStream
和 LongStream
,都实现了一些专用的 reduce
操作方法。在本案例中,我们将用 DoubleGenerator
生成一个 DoubleStream
,并使用 count()
、 sum()
、 average()
、 max()
和 min()
来获取元素的数量、总和、平均值、最大值和最小值。由于流只能被处理一次,因此每个操作都要创建一个新流。这些方法大多只用在 DoubleStream
、 IntStream
和 LongStream
里, Stream
中只有 count()
方法。它们中的一些返回了一个 Optional
对象。由于这样的对象可能没有值,因此请在获取值之前进行检查:
DoubleStream doubleStream = DoubleGenerator
.generateStreamFromList(numbers);
long numberOfElements = doubleStream.parallel().count();
System.out.printf("The list of numbers has %d elements.\n",
numberOfElements);
doubleStream = DoubleGenerator.generateStreamFromList(numbers);
double sum = doubleStream.parallel().sum();
System.out.printf("Its numbers sum %f.\n", sum);
doubleStream = DoubleGenerator.generateStreamFromList(numbers);
double average = doubleStream.parallel().average()
.getAsDouble();
System.out.printf("Its numbers have an average value of %f.\n",
average);
doubleStream = DoubleGenerator.generateStreamFromList(numbers);
double max = doubleStream.parallel().max().getAsDouble();
System.out.printf("The maximum value in the list is %f.\n",
max);
doubleStream = DoubleGenerator.generateStreamFromList(numbers);
double min = doubleStream.parallel().min().getAsDouble();
System.out.printf("The minimum value in the list is %f.\n",
min);
8.接下来使用第一个版本的 reduce()
方法。该方法接收一个满足结合律的 Binary- Operator
对象作为参数,其运算方法是接收两个相同类型的对象,并返回同类型的结果。这个归约操作在处理完流中的所有元素之后,所返回的 Optional
对象也有相同类型的泛型参数。请看如下代码,我们将用这个版本的 reduce()
方法,在一个列表中计算随机 Point
对象的坐标之和:
List<Point> points=PointGenerator.generatePointList(10000);
Optional<Point> point=points.parallelStream().reduce((p1,p2) -> {
Point p=new Point();
p.setX(p1.getX()+p2.getX());
p.setY(p1.getY()+p2.getY());
return p;
});
System.out.println(point.get().getX()+":"+point.get().getY());
9.然后,使用第二个版本的 reduce()
方法。它和前一个版本类似,但在本案例中,除了满足结合律的 BinaryOperator
之外,它还接收一个满足同一律的值(比如,0用于求总和,1用于求总乘积),并且返回一个跟元素相同类型的值。如果流是空的,则返回其接收的同一律值。在本案例中,我们用该版的 reduce()
方法计算了需要支付薪水的总额。使用 map()
方法把每个 Person
对象转换成为一个 int
值( Person
的薪水),这样 Stream
对象在执行 reduce()
方法时,就会拥有一些 int
值。更多关于 map()
方法的信息参见6.7节:
System.out.printf("Reduce, second version\n");
List<Person> persons = PersonGenerator.generatePersonList
(10000);
long totalSalary=persons.parallelStream().map
(p -> p.getSalary()).reduce(0, (s1,s2) -> s1+s2);
System.out.printf("Total salary: %d\n",totalSalary);
10.最后,使用第三个版本的 reduce()
方法。当归约结果和流元素的类型不同时,我们就可以使用该版本。首先要提供一个同一律值,它的类型和 reduce()
方法的返回值相同。然后提供一个实现了 BiFunction
接口的累加器,它接收一个与返回值相同类型的对象以及一个流元素,并用这两个参数生成一个和返回值相同类型的值。最后还要提供一个实现 BinaryOperator
接口的组合函数,它接收两个和 reduce()
方法返回值相同类型的对象,并生成一个该类型的对象。在下面的代码里,我们使用该版本的 reduce()
方法,在一个包含随机人员的列表中,计算出工资超过50000的人数:
Integer value=0;
value=persons.parallelStream().reduce(value, (n,p) -> {
if (p.getSalary() > 50000) {
return n+1;
} else {
return n;
}
}, (n1,n2) -> n1+n2);
System.out.printf("The number of people with a salary bigger
that 50,000 is %d\n",value);