当前位置:嗨网首页>书籍在线阅读

08-案例实现

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

案例实现

根据如下步骤实现本案例。

1.首先,实现这个例子所需的一些辅助类。6.2节所用的 PersonPersonGenerator 类也将在本节中使用。

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 类。该类内含两个双精度型属性( xy ),以及它们的 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 以及特殊的 DoubleStreamIntStreamLongStream ,都实现了一些专用的 reduce 操作方法。在本案例中,我们将用 DoubleGenerator 生成一个 DoubleStream ,并使用 count()sum()average()max()min() 来获取元素的数量、总和、平均值、最大值和最小值。由于流只能被处理一次,因此每个操作都要创建一个新流。这些方法大多只用在 DoubleStreamIntStreamLongStream 里, 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);