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

12-案例实现

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

案例实现

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

1.首先,实现将在本例中使用的辅助类。先创建 Person 类来存储人的基本数据,然后创建 PersonGenerator 类来生成一个包含随机人员的列表。这两个类的源码参见6.2节。

2.重写 Person 类的 toString() 方法,返回姓名:

@Override
public String toString() {
  return firstName + " " + lastName;
}

3.创建一个名为 Counter 的类。该类包含两个属性:一个名为 valueString 属性和一个名为 counterint 属性。然后生成这两个属性的 get()set() 方法。由于这个类的代码非常简单,此处不再展示。

4.现在,创建一个带有 main() 方法的 Main 类。然后用 PersonGenerator 类来创建一个包含随机 PersonList

public class Main {
  public static void main(String args[]) {
    List<Person> persons = PersonGenerator.generatePersonList
                                                        (100);

5.要实现的第一个收集操作是生成一个 Map ,其key是人名,其值是一个跟key同名的人的列表—用 Streamcollect() 方法和 Collectors.groupingByConcurrent 收集器来实现。然后使用 forEach() 方法来处理Map中所有人名,并把拥有相同人名的人数打印到控制台:这里把方法引用作为参数传递给了 groupingByConcurrent() 方法。如果只是和本例一样调用一个已有的方法,那就能通过lambda表达式来使用这种方法引用机制:

Map<String, List<Person>> personsByName = persons
                .parallelStream().collect(Collectors
                .groupingByConcurrent(Person::getFirstName));
personsByName.keySet().forEach(key -> {
  List<Person> listOfPersons = personsByName.get(key);
  System.out.printf("%s: There are %d persons with that name\n",
                    key, listOfPersons.size());

6.要实现的第二个收集操作是把所有人的名字串联起来,这里要使用 PersontoString() 方法、 Streamcollect() 方法以及 Collectorsjoining() 方法,通过它们把流的所有元素用指定的字符序列串联起来:

String message = persons.parallelStream().map
          (p -> p.toString()).collect(Collectors.joining(","));
System.out.printf("%s\n", message);

7.下一个要实现的收集操作是把人拆分为两组。第一组人的工资高于50000元,其余人都在第二组。这个操作的结果是一个 Map 对象, keyBoolean 值, value 是装有 Person 的列表。要实现这个操作,需要用到 Stream 类的 collect() 方法和 CollectorspartitioningBy() 方法,它接收一个 Boolean 型的参数表达式,通过 truefalse 来区分元素。最后使用 forEach() 把生成的列表的大小打印出来:

Map<Boolean, List<Person>> personsBySalary = persons
                .parallelStream().collect(Collectors
                .partitioningBy(p -> p.getSalary() > 50000));
personsBySalary.keySet().forEach(key -> {
  List<Person> listOfPersons = personsBySalary.get(key);
  System.out.printf("%s: %d \n", key, listOfPersons.size());
});

8.现在来实现一个生成 Map 的收集操作。 Mapkey 是人名, value 是串联起来的同名人的姓。在实现过程中会用到 Stream 类的 collect() 方法和 Collectors 类的 toConcurrentMap() 方法。我们要给该方法传递一个获取 key 的lambda表达式,一个获取 value 的lambda表达式,以及一个处理 Map 中已经存在指定 key 时的lambda表达式。最后使用 forEach() 方法打印所有的 keyvalue

ConcurrentMap<String, String> nameMap = persons
                .parallelStream().collect(Collectors
                .toConcurrentMap(p -> p.getFirstName(),
                                 p -> p.getLastName(),
                                 (s1, s2) -> s1 + ", " + s2));
nameMap.forEach((key, value) -> {
  System.out.printf("%s: %s \n", key, value);
});

9.到目前为止,在所有例子里实现的 collect() 方法都是接收一个 Collector 接口的实现。不过,还有另外一种版本的 collect() 方法。下面用这个版本的 collect() 方法来实现一个收集操作,生成一个工资高于50000的人员列表。要给 collect() 方法传递一个表达式来创建列表(用 List::new 方法),传递一个lambda表达式来处理列表和元素,以及一个用来处理两个列表的表达式(用 List::addAll 方法):

List<Person> highSalaryPeople = persons
                .parallelStream().collect(
  ArrayList::new, (list, person) -> {
    if (person.getSalary() > 50000) {
      list.add(person);
    }
  },
  ArrayList::addAll
);
System.out.printf("High Salary People: %d\n",
                  highSalaryPeople.size());

10.最后,实现一个生成 ConcurrentHashMap 的例子, map 将包含 人员 列表中人的名字,以及每个名字出现的次数。以人名作为 key ,以 Counter 对象作为值。 collect 方法的第一个参数用于创建一个新的 ConcurrentHashMap 对象。第二个参数是 BiConsumer 接口的一个实现,它用一个 ConcurrentHashMap 对象和一个 Person 对象作为参数。我们首先使用 mapcomputeIfPresent() 方法,在人名存在时递增 Counter 。然后使用 mapcomputeIfAbsent() 方法,在人名不存在时将其插入。 collect() 方法的第三个参数也是一个 BiConsumer 接口的实现,它接收两个 ConcurrentHashMap 对象,用 merge() 方法来处理第二个 map 中的所有元素,把不存在于第一个 map 中的元素插入第一个 map 中,或存在时增加第一个 mapcounter

System.out.printf("Collect, second example\n");
ConcurrentHashMap<String, Counter> peopleNames = persons
                        .parallelStream().collect(
  ConcurrentHashMap::new, (map, person) -> {
    map.computeIfPresent(person.getFirstName(), (name,
                                                 counter) -> {
      counter.increment();
      return counter;
    });
    map.computeIfAbsent(person.getFirstName(), name -> {
      Counter c=new Counter();
      c.setValue(name);
      return c;
    });
  },
  (map1, map2) -> {
    map2.forEach (10, (key, value) -> {
      map1.merge(key, value, (v1,v2) -> {
        v1.setCounter(v1.getCounter()+v2.getCounter());
        return v1;
      });
    });
  });
  peopleNames.forEach((name, counter) -> {
    System.out.printf("%s: %d\n", name, counter.getCounter());
  });