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));