24-案例实现
案例实现
根据如下步骤实现本案例。
1.首先,实现将在本案例中使用的辅助类。先创建 Person
类来存储一个人的基本属性,然后创建 PersonGenerator
类来生成一个包含随机人员的 List
。这两个类的源代码参见6.5节。
2.创建一个名为 BasicPerson
的类。它包含一个 String
类型的 name
属性和一个 long
型的 age
属性。为这两个属性创建 get()
和 set()
方法。由于这个类的代码非常简单,因此此处不再展示。
3.再创建一个辅助类 FileGenerator
。该类包含一个 generateFile()
方法—用于接收所模拟文件的行数,并返回一个包含 String
的 List
作为文件的内容。
public class FileGenerator {
public static List<String> generateFile(int size) {
List<String> file=new ArrayList<>();
for (int i=0; i<size; i++) {
file.add("Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Morbi lobortis
cursus venenatis. Mauris tempus elit ut
malesuada luctus. Interdum et malesuada fames
ac ante ipsum primis in faucibus. Phasellus
laoreet sapien eu pulvinar rhoncus. Integer vel
ultricies leo. Donec vel sagittis nibh.
Maecenas eu quam non est hendrerit pu");
}
return file;
}
}
4.然后创建一个包含 main()
方法的 Main
类。在 main()
方法里,先用 PersonGenerator
创建一个 List
—它应包含随机的 Person
对象:
public class Main {
public static void main(String[] args) {
// 创建包含随机人员的List
List<Person> persons = PersonGenerator.generatePersonList(100);
5.使用 mapToDouble()
把 Person
对象转换成包含双精度型数字的 DoubleStream
。先使用 parallelStream()
创建并行流,然后再使用 mapToDouble()
方法,传入一个接收 Person
对象的lambda表达式作为参数,并返回他的工资,其中工资是一个双精度型的数字。然后使用 distinct()
方法去除重复值,并使用 forEach()
方法把工资打印到控制台。另外,使用 count()
方法把不同元素的数量写到控制台:
DoubleStream ds = persons.parallelStream().mapToDouble
(p -> p.getSalary());
ds.distinct().forEach(d -> {
System.out.printf("Salary: %f\n", d);
});
ds = persons.parallelStream().mapToDouble(p -> p.getSalary());
long size = ds.distinct().count();
System.out.printf("Size: %d\n", size);
6.现在将流中的 Person
对象转换成 BasicPerson
对象。使用 parallelStream()
方法来创建流,并使用 map()
方法来转换对象。 map()
方法接收一个lambda表达式作为参数,并用这个表达式接收一个 Person
对象,然后创建一个新的 BasicPerson
对象并对其属性赋值。接着使用 forEach()
方法把 BasicPerson
对象的属性值打印到控制台:
List<BasicPerson> basicPersons = persons.parallelStream().map
(p -> {
BasicPerson bp = new BasicPerson();
bp.setName(p.getFirstName() + " " + p.getLastName());
bp.setAge(getAge(p.getBirthDate()));
return bp;
}).collect(Collectors.toList());
basicPersons.forEach(bp -> {
System.out.printf("%s: %d\n", bp.getName(), bp.getAge());
});
7.最后,学习如何处理一个中间操作返回 Stream
的情况。在这种情况下,我们将处理一个包含流的 Stream
,不过可以使用 flatMap()
方法将所有这些 Stream
对象串联成唯一的一个 Stream
。使用 FileGenerator
生成一个包含100个元素的 List
,然后用 parallelStream()
方法创建一个并行流。我们将用 split()
方法把每行拆分成多个单词,并用 Stream
类的 of()
方法把结果数组转换成 Stream
。如果使用 map()
方法,则会得到一个包含流的 Stream
;而使用 flatMap()
方法,就能得到唯一的一个 Stream
,它包含整个 List
中所有单词的 String
对象。接着使用 filter()
去除长度等于0的单词,使用 sorted()
方法排序流,使用 groupingByConcurrent()
方法收集流得到一个 Map
,其 key
是这些单词, value
是每个单词出现在流中的次数:
List<String> file=FileGenerator.generateFile(100);
Map<String, Long> wordCount = file.parallelStream()
.flatMap(line -> Stream.of(line.split("[ ,.]")))
.filter(w -> w.length() > 0).sorted()
.collect(Collectors.groupingByConcurrent(e -> e, Collectors
.counting()));
wordCount.forEach((k, v) -> {
System.out.printf("%s: %d\n", k, v);
});
8.最后还要实现前面代码中使用的 getAge()
方法。该方法接收一个人的出生日期并返回他的年龄:
private static long getAge(Date birthDate) {
LocalDate start=birthDate.toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate now=LocalDate.now();
long ret = ChronoUnit.YEARS.between(start, now);
return ret;
}