04-案例实现
案例实现
在本节中,我们将实现一个案例,帮助读者掌握如何从前面描述的源上创建流。请根据如下步骤来实现本案例。
1.首先,要实现这个例子所需的一些辅助类。创建一个名为 Person
的类。该类包含几个不同类型的属性,即 String
、 int
、 double
和 Date
:
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
对象。这里假设,如果两个 Person
的 firstName
和 lastName
都相同,那么就是同一个人:
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.最后,我们把两个流串联起来形成一个流。首先,用 Stream
的 of()
方法创建两个包含 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));