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

04-案例实现

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

案例实现

在本节中,我们将实现一个案例,帮助读者掌握如何从前面描述的源上创建流。请根据如下步骤来实现本案例。

1.首先,要实现这个例子所需的一些辅助类。创建一个名为 Person 的类。该类包含几个不同类型的属性,即 StringintdoubleDate

public class Person implements Comparable<Person> {
  private int id;
  private String firstName;
  private String lastName;
  private Date birthDate;
  private int salary;
  private double coeficient;

2.创建方法以设置和获取属性值。实现 compareTo() 方法,以比较两个 Person 对象。这里假设,如果两个 PersonfirstNamelastName 都相同,那么就是同一个人:

  public int compareTo(Person otherPerson) {
    int compareLastNames = this.getLastName().compareTo
                                (otherPerson.getLastName());
    if (compareLastNames != 0) {
      return compareLastNames;
    } else {
    return this.getFirstName().compareTo
                                (otherPerson.getFirstName());
  }
}

3.创建一个名为 PersonGenerator 的类,用它来创建一个包含随机 Person 的列表对象。在该类中实现一个静态方法 generatePersonList() ,以接收所要创建的人数量,并返回一个有此数量人员的 List<Person> 。下面我们提供了一个版本(开发者可以随意修改这个版本):

public class PersonGenerator {
  public static List<Person> generatePersonList (int size) {
    List<Person> ret = new ArrayList<>();
    String firstNames[] = {"Mary","Patricia","Linda",
                           "Barbara","Elizabeth","James",
                           "John","Robert","Michael",
                           "William"};
    String lastNames[] = {"Smith","Jones","Taylor",
                          "Williams","Brown","Davies",
                          "Evans","Wilson","Thomas",
                          "Roberts"};
    Random randomGenerator=new Random();
    for (int i=0; i<size; i++) {
      Person person=new Person();
      person.setId(i);
      person.setFirstName(firstNames[randomGenerator
                                     .nextInt(10)]);
      person.setLastName(lastNames[randomGenerator
                                   .nextInt(10)]);
      person.setSalary(randomGenerator.nextInt(100000));
      person.setCoeficient(randomGenerator.nextDouble()*10);
      Calendar calendar=Calendar.getInstance();
      calendar.add(Calendar.YEAR, -randomGenerator
                                         .nextInt(30));
      Date birthDate=calendar.getTime();
      person.setBirthDate(birthDate);
      ret.add(person);
    }
    return ret;
  }

4.现在来创建一个名为 MySupplier 的类,实现 Supplier 接口,并用 String 类作为泛型参数:

public class MySupplier implements Supplier<String> {

5.声明一个私有的 AtomicInteger 属性,将其命名为 counter ,并在 MySupplier 的构造器中初始化它:

private final AtomicInteger counter;
public MySupplier() {
  counter=new AtomicInteger(0);
}

6.实现 Supplier 接口定义的 get() 方法。该方法用于返回流中的下一个元素:

  @Override
  public String get() {
    int value=counter.getAndAdd(1);
    return "String "+value;
  }
}

7.现在,创建一个名为 Main 的类,并在其中实现 main() 方法:

public class Main {
  public static void main(String[] args) {

8.首先,用一个包含元素的列表来创建 Stream 对象。通过 PersonGenerator 类来生成一个包含10000个 Person 对象列表,使用其 parallelStream() 方法创建 Stream 。然后,用 Stream 对象的 count() 方法获取这个流中元素的数量:

System.out.printf("From a Collection:\n");
List<Person> persons=PersonGenerator.generatePersonList(10000);
Stream<Person> personStream=persons.parallelStream();
System.out.printf("Number of persons: %d\n",
                  personStream.count());

9.接下来,我们将用生成器来创建 Stream 。先创建一个 MySupplier 对象,并将其作为参数传递给 Stream 类的静态方法 generate() 。然后使用 parallel() 方法将其转换为并行流,最后用 limit() 方法获取该流的前10个元素,并用 forEach() 方法打印元素:

System.out.printf("From a Supplier:\n");
Supplier<String> supplier=new MySupplier();
Stream<String> generatorStream=Stream.generate(supplier);
generatorStream.parallel().limit(10).forEach(s->
                                   System.out.printf("%s\n",s));

10.接着,在一个定义好的元素列表上创建流。使用 Stream 类的静态方法 of() 创建 Stream 。该方法接收一个变长的参数列表。在本案例中,我们传递了3个 String 对象。然后使用流的 parallel() 方法将其转换为并行流,并用 forEach() 方法把值打印到控制台:

System.out.printf("From a predefined set of elements:\n");
Stream<String> elementsStream=Stream.of("Peter","John","Mary");
elementsStream.parallel().forEach(element ->
                            System.out.printf("%s\n", element));

11.现在,我们来创建一个按行读取文件的流。首先,创建一个 BufferedReader 对象来读取一个文件。其次,使用 BufferedReader 类的 lines() 方法获取一个包含 String 对象的流。该流的每个元素都是文件里的某一行。接着,使用 parallel() 方法获取并行流,并用 count() 方法获取元素的数量。最后,记得关闭 BufferedReader 对象:

System.out.printf("From a File:\n");
try (BufferedReader br = new BufferedReader(new
                         FileReader("data\\nursery.data"));) {
  Stream<String> fileLines = br.lines();
  System.out.printf("Number of lines in the file: %d\n\n",
                    fileLines.parallel().count());
  System.out.printf("********************************
                     ************************\n");
  System.out.printf("\n");
  br.close();
} catch (FileNotFoundException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

12.现在,我们来创建一个处理文件夹内容的 Stream 。首先,使用 Files 类的 list() 方法从代表文件夹的 Path 对象上获取流。其次,使用 Stream 对象的 parallel() 方法得到并行流,接着用 count()方 法计算元素的数量。最后,必须要在本案例中用 close() 方法把流关闭:

System.out.printf("From a Directory:\n");
try {
  Stream<Path> directoryContent = Files.list(Paths.get
                            (System.getProperty("user.home")));
  System.out.printf("Number of elements (files and
                     folders):%d\n\n",
                    directoryContent.parallel().count());
  directoryContent.close();
  System.out.printf("********************************
                     ************************\n");
  System.out.printf("\n");
} catch (IOException e) {
  e.printStackTrace();
}

13.下一个用来创建流的源是数组。首先,创建一个字符串数组。其次,用 Arrays 类的 stream() 方法从这个数组上创建流。最后,用流的 parallel() 方法把其转化成并行流,并用 forEach() 方法把该流的元素打印到控制台:

System.out.printf("From an Array:\n");
String array[]={"1","2","3","4","5"};
Stream<String> streamFromArray=Arrays.stream(array);
streamFromArray.parallel().forEach(s->System.out.printf("%s : ",
                                                        s));

14.现在,我们来创建一个随机的双精度型数字流。首先,创建一个 Random 对象,用其 doubles() 方法创建一个 DoubleStream 对象。我们把数字 10 作为参数传递给该方法,这样,要创建的流就会有 10 个元素。最后,用 parallel() 方法把该流转化成并行流,用 peek() 方法把每个元素写到控制台上,用 average() 方法计算所有元素的平均值,用 getAsDouble() 方法把值从 average() 方法返回的 Optional 对象里取出来:

Random random = new Random();
DoubleStream doubleStream = random.doubles(10);
double doubleStreamAverage = doubleStream.parallel().peek
                             (d -> System.out.printf("%f :",d))
                             .average().getAsDouble();

15.最后,我们把两个流串联起来形成一个流。首先,用 Streamof() 方法创建两个包含 String 对象的流。其次,用 Stream 类的 concat() 方法把这两个流连成一个。最后,用 Stream 类的 parallel() 方法得到并行流,并用 forEach() 方法把所有元素写到控制台上:

System.out.printf("Concatenating streams:\n");
Stream<String> stream1 = Stream.of("1", "2", "3", "4");
Stream<String> stream2 = Stream.of("5", "6", "7", "8");
Stream<String> finalStream = Stream.concat(stream1, stream2);
finalStream.parallel().forEach(s -> System.out.printf("%s : ",
                                                      s));