Java 8 Lambda表示式與Stream 流結合使用
使用Lambdas和Streams
Stream是對集合的包裝,通常和lambda一起使用。 使用lambdas可以支援許多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等。 同樣,Stream使用懶運算,他們並不會真正地讀取所有資料,遇到像getFirst() 這樣的方法就會結束鏈式語法。
在接下來的例子中,我們將探索lambdas和streams 能做什麼。 我們建立了一個Person類並使用這個類來新增一些資料到list中,將用於進一步流操作。 Person 只是一個簡單的POJO類:
public class Person { private String firstName, lastName, job, gender; private int salary, age; public Person(String firstName, String lastName, String job, String gender, int age, int salary) { this.firstName = firstName; this.lastName = lastName; this.gender = gender; this.age = age; this.job = job; this.salary = salary; } // Getter and Setter // . . . . . }
接下來,我們將建立兩個list,都用來存放Person物件:
List<Person> javaProgrammers = new ArrayList<Person>() { { add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000)); add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500)); add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800)); add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600)); add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200)); add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900)); add(new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300)); add(new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700)); add(new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000)); add(new Person("Addison", "Pam", "Java programmer", "female", 34, 1300)); } }; List<Person> phpProgrammers = new ArrayList<Person>() { { add(new Person("Jarrod", "Pace", "PHP programmer", "male", 34, 1550)); add(new Person("Clarette", "Cicely", "PHP programmer", "female", 23, 1200)); add(new Person("Victor", "Channing", "PHP programmer", "male", 32, 1600)); add(new Person("Tori", "Sheryl", "PHP programmer", "female", 21, 1000)); add(new Person("Osborne", "Shad", "PHP programmer", "male", 32, 1100)); add(new Person("Rosalind", "Layla", "PHP programmer", "female", 25, 1300)); add(new Person("Fraser", "Hewie", "PHP programmer", "male", 36, 1100)); add(new Person("Quinn", "Tamara", "PHP programmer", "female", 21, 1000)); add(new Person("Alvin", "Lance", "PHP programmer", "male", 38, 1600)); add(new Person("Evonne", "Shari", "PHP programmer", "female", 40, 1800)); } };
現在我們使用forEach方法來迭代輸出上述列表:
System.out.println("所有程式設計師的姓名:");
javaProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
phpProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
我們同樣使用forEach方法,增加程式設計師的工資5%:
System.out.println("給程式設計師加薪 5% :"); Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary()); javaProgrammers.forEach(giveRaise); phpProgrammers.forEach(giveRaise);
另一個有用的方法是過濾器filter() ,讓我們顯示月薪超過1400美元的PHP程式設計師:
System.out.println("下面是月薪超過 $1,400 的PHP程式設計師:")
phpProgrammers.stream()
.filter((p) -> (p.getSalary() > 1400))
.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
我們也可以定義過濾器,然後重用它們來執行其他操作:
// 定義 filters
Predicate<Person> ageFilter = (p) -> (p.getAge() > 25);
Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400);
Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender()));
System.out.println("下面是年齡大於 24歲且月薪在$1,400以上的女PHP程式設計師:");
phpProgrammers.stream()
.filter(ageFilter)
.filter(salaryFilter)
.filter(genderFilter)
.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
// 重用filters
System.out.println("年齡大於 24歲的女性 Java programmers:");
javaProgrammers.stream()
.filter(ageFilter)
.filter(genderFilter)
.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
使用limit方法,可以限制結果集的個數:
System.out.println("最前面的3個 Java programmers:");
javaProgrammers.stream()
.limit(3)
.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
System.out.println("最前面的3個女性 Java programmers:");
javaProgrammers.stream()
.filter(genderFilter)
.limit(3)
.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
排序呢? 我們在stream中能處理嗎? 答案是肯定的。 在下面的例子中,我們將根據名字和薪水排序Java程式設計師,放到一個list中,然後顯示列表:
System.out.println("根據 name 排序,並顯示前5個 Java programmers:");
List<Person> sortedJavaProgrammers = javaProgrammers
.stream()
.sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName())))
.limit(5)
.collect(toList());
sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));
System.out.println("根據 salary 排序 Java programmers:");
sortedJavaProgrammers = javaProgrammers
.stream()
.sorted( (p, p2) -> (p.getSalary() - p2.getSalary()) )
.collect( toList() );
sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));
如果我們只對最低和最高的薪水感興趣,比排序後選擇第一個/最後一個 更快的是min和max方法
System.out.println("工資最低的 Java programmer:");
Person pers = javaProgrammers
.stream()
.min((p1, p2) -> (p1.getSalary() - p2.getSalary()))
.get()
System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary())
System.out.println("工資最高的 Java programmer:");
Person person = javaProgrammers
.stream()
.max((p, p2) -> (p.getSalary() - p2.getSalary()))
.get()
System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())
上面的例子中我們已經看到 collect 方法是如何工作的。 結合 map 方法,我們可以使用 collect 方法來將我們的結果集放到一個字串,一個 Set 或一個TreeSet中:
System.out.println("將 PHP programmers 的 first name 拼接成字串:");
String phpDevelopers = phpProgrammers
.stream()
.map(Person::getFirstName)
.collect(joining(" ; ")); // 在進一步的操作中可以作為標記(token)
System.out.println("將 Java programmers 的 first name 存放到 Set:");
Set<String> javaDevFirstName = javaProgrammers
.stream()
.map(Person::getFirstName)
.collect(toSet());
System.out.println("將 Java programmers 的 first name 存放到 TreeSet:");
TreeSet<String> javaDevLastName = javaProgrammers
.stream()
.map(Person::getLastName)
.collect(toCollection(TreeSet::new));
Streams 還可以是並行的(parallel)。 示例如下:
System.out.println("計算付給 Java programmers 的所有money:");
int totalSalary = javaProgrammers
.parallelStream()
.mapToInt(p -> p.getSalary())
.sum();
我們可以使用summaryStatistics方法獲得stream 中元素的各種彙總資料。 接下來,我們可以訪問這些方法,比如getMax, getMin, getSum或getAverage:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
IntSummaryStatistics stats = numbers
.stream()
.mapToInt((x) -> x)
.summaryStatistics();
System.out.println("List中最大的數字 : " + stats.getMax());
System.out.println("List中最小的數字 : " + stats.getMin());
System.out.println("所有數字的總和 : " + stats.getSum());
System.out.println("所有數字的平均值 : " + stats.getAverage());
感謝您的觀看