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);