Tips 本篇文章主要是RxJava官方文档的辅料,里面太多的Lambda表达式,没有一些了解的确难以看懂,因为是主要的重心还是落在RxJava上,所以本文概述一下如何在Android Studio中使用以及各个表达式的意思,还有与Rxjava及其相似的stream。官方文档 如何描述Lambda表达式:
Lambda expressions are a new and important feature included in Java SE 8. They provide a clear and concise way to represent one method interface using an expression. Lambda expressions also improve the Collection libraries making it easier to iterate through, filter, and extract data from a Collection. In addition, new concurrency features improve performance in multicore environments.
这段话指出了在java8中lambda表达式三个主要的作用:简洁的方式呈现接口;提高集合迭代,过滤和扩展的性能;提高多核环境下并发的性能。具体的翻译还是大家自行去理解,中英转换肯定会出现一定的偏差。
软硬件环境
JDK 8
NetBeans 7.4 (这个只是IDE 在Android Studio中同样是可以使用的)
Lambda应用场景 Anonymous Inner Class 匿名内部类,用过java的人这个应该都知道就不再赘述
1 2 3 4 5 6 7 8 9 10 11 JButton jb1 = new JButton(); jb1.addActionListener(new ActionListener() { @Override public void actionPerformed (ActionEvent e) { System.out.println("xxx" ); } }); JButton jb = new JButton(); jb.addActionListener((e) -> System.out.println());
Functional Interface 在java中,一个interface里面只有一个需要实现的方法,这种形式的接口就被称作为Functional Interface,也被叫做SAM.(Single Abstract Method)
1 2 3 4 5 6 7 8 public interface ActionListener extends EventListener { /** * Invoked when an action occurs. */ public void actionPerformed(ActionEvent e); }
Lambda Expression Syntax λ表达式的语法,通常λ表达式可以将5行代码,转换成一行代码来表示,上面的匿名内部类便是例子,λ表达式的语法由如下三个部分组成:
参数列表
箭头
方法体
(int x,int y)
->
x + y
lambda表达式实例 Listener Lambda 1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static void listenerLambda() { // Listener Lambda JButton jb1 = new JButton(); jb1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("xxx"); } }); // lambda表达式的方式 JButton jb = new JButton(); jb.addActionListener((e) -> System.out.println()); }
Comparator Lambda 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private static void compatorLambda() { // sort with inner class List<Person> personList = new ArrayList<>(); personList.add(new Person("zk")); personList.add(new Person("ak")); System.out.println("sort with inner class"); Collections.sort(personList, new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { // 按照字典序排列 person return o1.getSurName().compareTo(o2.getSurName()); } }); for (Person p: personList) { System.out.println(p.getSurName()); } System.out.println("sort with lambda"); // sort with lambda Collections.sort(personList, (p1,p2)->p1.getSurName().compareTo(p2.getSurName())); for (Person p: personList) { System.out.println(p.getSurName()); } }
Runnable Lambda 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private static void runnableLambda() { // 传统模式 Runnable r1 = new Runnable() { @Override public void run() { System.out.println("Tran A"); System.out.println("Tran B"); } }; // lambda Runnable r2 = () -> System.out.print("Lambda A"); System.out.print("Lambda B"); r1.run(); r2.run(); }
Improving Code with Lambda Expression 使用Lambda优化代码。代码优化这件事可轻可重,像我写代码的主要目的就是奔着功能去,一往无前,有bug回头改,往往都是一去不返。代码优化有很多方面,像6大设计原则,23种设计模式等等,今天得例子要验证得Principle叫做 — ‘Don’t Repeat Yourself ‘ 简称 (DRY),不得不说所有得原则全称都不如简称有格调。
那下面我们就来验证一下lambda相对于原有得做法到底 DRY 在哪里:
1.场景
有一群人来面试,只招聘司机、应征入伍、飞行员,面试得条件如下:
司机 : 年纪超过16
入伍 : 男性年龄在18-25之间
飞行员:年龄在23 到 65之间
Person 字段
1 2 3 4 5 6 7 8 9 public class Person { private String givenName; private String surName; private int age; private Gender gender; private String eMail; private String phone; private String address; }
2.创建person List
怎么创建比较随意,我这里就按照官网得方式来创建(在上一篇RxJava中有关于设计模式得附录)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public static List<Person> createShortList() { List<Person> people = new ArrayList<>(); people.add( new Person.Builder(). givenName("Bob") .surName("Baker") .age(21) .gender(Gender.MALE) .email("bob.baker@example.com") .phoneNumber("201-121-4678") .address("44 4th St, Smallville, KS 12333") .build() ); people.add( new Person.Builder() .givenName("Jane") .surName("Doe") .age(25) .gender(Gender.FEMALE) .email("jane.doe@example.com") .phoneNumber("202-123-4678") .address("33 3rd St, Smallville, KS 12333") .build() ); people.add( new Person.Builder() .givenName("John") .surName("Doe") .age(25) .gender(Gender.MALE) .email("john.doe@example.com") .phoneNumber("202-123-4678") .address("33 3rd St, Smallville, KS 12333") .build() ); return people; }
选出满足条件的人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class RoboContactMethods { public void callDrivers(List<Person> pl) { for (Person p : pl) { if (p.getAge() >= 16) { roboCall(p); } } } public void emailDraftees(List<Person> pl) { for (Person p : pl) { if (p.getAge() >= 18 && p.getAge() <= 25 && p.getGender() == Gender.MALE) { roboEmail(p); } } } public void mailPilots(List<Person> pl) { for (Person p : pl) { if (p.getAge() >= 23 && p.getAge() <= 65) { roboMail(p); } } } public void roboCall(Person p) { System.out.println("Calling " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getPhone()); } public void roboEmail(Person p) { System.out.println("EMailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.geteMail()); } public void roboMail(Person p) { System.out.println("Mailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getAddress()); } }
我看这段代码是没问题的,for循环迭代选出满足条件的人,完全没毛病;那我们来看看官方的犊子是怎么演的。
没有遵循DRY原则
需要大量方法来实现每个用例
上述代码不灵活,如果招聘条件发生变化,那么将引起大量的更改,可维护性不强
4.第一次重构
这次我们将上述的几个问题列入考虑,其实,我感觉我的翻译貌似出了点小差错,或者是我没明白他是什么意思,除了最后一项可以理解之外,其他的情况没弄懂是什么意思,再或者是本身语言的限制只能优化最后一项,那么下面看看,该如何重构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class RoboContactMethods2 { public void callDrivers(List<Person> pl) { for (Person p : pl) { if (isDriver(p)) { roboCall(p); } } } public void emailDraftees(List<Person> pl) { for (Person p : pl) { if (isDraftee(p)) { roboEmail(p); } } } public void mailPilots(List<Person> pl) { for (Person p : pl) { if (isPilot(p)) { roboMail(p); } } } public boolean isDriver(Person p) { return p.getAge() >= 16; } public boolean isDraftee(Person p) { return p.getAge() >= 18 && p.getAge() <= 25 && p.getGender() == Gender.MALE; } public boolean isPilot(Person p) { return p.getAge() >= 23 && p.getAge() <= 65; } public void roboCall(Person p) { System.out.println("Calling " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getPhone()); } public void roboEmail(Person p) { System.out.println("EMailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.geteMail()); } public void roboMail(Person p) { System.out.println("Mailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getAddress()); } }
搜索条件被封装进方法中,较之前的代码而言确实有一定的提升,条件可以被反复利用并且可以更方便的更改。但是,还是有很多重复的地方,是不是没有更好的办法呢?(······肯定是有的,要不我说个球)
在使用lambda之前先看看还有什么能改进的或者是为lambda做一些铺垫。上述的代码,其实并不符合开闭原则(OCP – 原则上对修改关闭,对扩展开放),这段程序可能发生改变是招聘条件,那么我们让调用程序自己去维护,就更进一步的优化了。
将条件抽象成接口,让调用者自己去维护,接口如下:
1 2 3 public interface MyTest<T> { public boolean test(T t); }
RoboContactsAnon.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.example.lambda; import java.util.List; import java.util.function.Predicate; /** * @author MikeW */ public class RoboContactsAnon { public void phoneContacts(List<Person> pl, MyTest<Person> pred) { for (Person p : pl) { if (pred.test(p)) { roboCall(p); } } } public void emailContacts(List<Person> pl, MyTest<Person> pred) { for (Person p : pl) { if (pred.test(p)) { roboEmail(p); } } } public void mailContacts(List<Person> pl, MyTest<Person> pred) { for (Person p : pl) { if (pred.test(p)) { roboMail(p); } } } public void roboCall(Person p) { System.out.println("Calling " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getPhone()); } public void roboEmail(Person p) { System.out.println("EMailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getEmail()); } public void roboMail(Person p) { System.out.println("Mailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getAddress()); } }
RoboCallTest03.java 调用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class RoboCallTest03 { public static void main(String[] args) { List<Person> pl = Person.createShortList(); RoboContactsAnon robo = new RoboContactsAnon(); System.out.println("\n==== Test 03 ===="); System.out.println("\n=== Calling all Drivers ==="); robo.phoneContacts(pl, new MyTest<Person>(){ @Override public boolean test(Person p){ return p.getAge() >=16; } } ); System.out.println("\n=== Emailing all Draftees ==="); robo.emailContacts(pl, new MyTest<Person>(){ @Override public boolean test(Person p){ return p.getAge() >= 18 && p.getAge() <= 25 && p.getGender() == Gender.MALE; } } ); System.out.println("\n=== Mail all Pilots ==="); robo.mailContacts(pl, new MyTest<Person>(){ @Override public boolean test(Person p){ return p.getAge() >= 23 && p.getAge() <= 65; } } ); } }
仅通过java8之前得方式,程序看起来已经符合OCP的原则;在前面提到过SAM这种形式是可以用,lambda来表示的。那么看看如何去用lambda,来进一步的优化上面的程序
lambda 优化
在java.util.function包中提供了一种形式类似的MyTest的接口,Predicate:
1 2 3 public interface Predicate<T> { public boolean test(T t); }
RoboContactsLambda.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.example.lambda; import java.util.List; import java.util.function.Predicate; /** * @authorzhoukan */ public class RoboContactLambda { public void phoneContacts(List<Person> pl, Predicate<Person> pred) { for (Person p : pl) { if (pred.test(p)) { roboCall(p); } } } public void emailContacts(List<Person> pl, Predicate<Person> pred) { for (Person p : pl) { if (pred.test(p)) { roboEmail(p); } } } public void mailContacts(List<Person> pl, Predicate<Person> pred) { for (Person p : pl) { if (pred.test(p)) { roboMail(p); } } } public void roboCall(Person p) { System.out.println("Calling " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getPhone()); } public void roboEmail(Person p) { System.out.println("EMailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getEmail()); } public void roboMail(Person p) { System.out.println("Mailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getAddress()); } }
Mytest接口被更换成了Predicate,调用程序的代码片段如下
1 2 3 4 5 6 7 8 public static void main(String[] args){ List<Person> pl = Person.createShortList(); RoboContactLambda robo = new RoboContactLambda(); Predicate<Person> allDrivers = p -> p.getAge() >= 16; robo.phoneContacts(pl, allDrivers); }
当然即使不适用util.function提供的接口,也是可以实现了,只要满足lambda表达式的场景就好:1 2 3 4 5 6 7 8 9 robo.mailContacts(pl, /*new MyTest<Person>(){ @Override public boolean test(Person p){ return p.getAge() >= 23 && p.getAge() <= 65; } }*/ (p) -> p.getAge() > 23 && p.getAge() <= 65 );
The java.util.function 包 function包提供了几种方便去使用lambda的interface,当然不仅仅是给lambda表达式使用,所有诸如上述的优化都是可以考虑用这些方法的,确实我看到这里就有点抑制不住内心的小狂喜,lambda的这些function不就是Rxjava中常用的操作符嘛,这么麻烦的工作算是没白做,就下面的需求,我们来体验一下她的魅力。
Predicate: A property of the object passed as argument
Consumer: An action to be performed with the object passed as argument
Function: Transform a T to a U
Supplier: Provide an instance of a T (such as a factory)
UnaryOperator: A unary operator from T -> T
BinaryOperator: A binary operator from (T, T) -> T
输出东方人和西方人的信息
上面的personList(求职者),要将他们的信息分别发给,老板和老板娘,他们一个是中国人,一个是美国人;由于习惯不同,西方习惯姓在后名在前(分别对应Given name 和 surname),中国的习惯我就不提了。
传统的方式
person.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void printWesternName() { System.out.println("\nName: " + this.getGivenName() + " " + this.getSurName() + "\n" + "Age: " + this.getAge() + " " + "Gender: " + this.getGender() + "\n" + "EMail: " + this.geteMail() + "\n" + "Phone: " + this.getPhone() + "\n" + "Address: " + this.getAddress()); } public void printEasternName() { System.out.println("\nName: " + this.getSurName() + " " + this.getGivenName() + "\n" + "Age: " + this.getAge() + " " + "Gender: " + this.getGender() + "\n" + "EMail: " + this.geteMail() + "\n" + "Phone: " + this.getPhone() + "\n" + "Address: " + this.getAddress()); }
使用Function Interface的方式 1 2 3 public interface Function<R,T>{ public R apply(T t); }
指定两个泛型以T作为输入,R作为输出,那么对于上述场景而言 -> Function<string,person>,用function来更灵活的实现打印方法:
Person.java
1 2 3 public String printCustom(Function <Person, String> f){ return f.apply(this); }
调用程序 NameTestNew.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public class NameTestNew { public static void main(String[] args) { System.out.println("\n==== NameTestNew02 ==="); List<Person> list1 = Person.createShortList(); // Print Custom First Name and e-mail System.out.println("===Custom List==="); for (Person person : list1) { System.out.println( person.printCustom(p -> "Name: " + p.getGivenName() + " EMail: " + p.getEmail()) ); } // Define Western and Eastern Lambdas Function<Person, String> westernStyle = p -> { return "\nName: " + p.getGivenName() + " " + p.getSurName() + "\n" + "Age: " + p.getAge() + " " + "Gender: " + p.getGender() + "\n" + "EMail: " + p.getEmail() + "\n" + "Phone: " + p.getPhone() + "\n" + "Address: " + p.getAddress(); }; Function<Person, String> easternStyle = p -> "\nName: " + p.getSurName() + " " + p.getGivenName() + "\n" + "Age: " + p.getAge() + " " + "Gender: " + p.getGender() + "\n" + "EMail: " + p.getEmail() + "\n" + "Phone: " + p.getPhone() + "\n" + "Address: " + p.getAddress(); // Print Western List System.out.println("\n===Western List==="); for (Person person : list1) { System.out.println( person.printCustom(westernStyle) ); } // Print Eastern List System.out.println("\n===Eastern List==="); for (Person person : list1) { System.out.println( person.printCustom(easternStyle) ); } } }
第一次循环只输出了名和email,所有有效的表达式都能作为printCustom的参数;第二次,首先将东方人和西方人的输出方式定义为Fucntion,并当作参数传入printCustom中。lambda表达式利于扩展和反复利用的优势得以体现。
输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 ==== NameTestNew02 === ===Custom List=== Name: Bob EMail: bob.baker@example.com Name: Jane EMail: jane.doe@example.com Name: John EMail: john.doe@example.com Name: James EMail: james.johnson@example.com Name: Joe EMail: joebob.bailey@example.com Name: Phil EMail: phil.smith@examp;e.com Name: Betty EMail: betty.jones@example.com ===Western List=== Name: Bob Baker Age: 21 Gender: MALE EMail: bob.baker@example.com Phone: 201-121-4678 Address: 44 4th St, Smallville, KS 12333 Name: Jane Doe Age: 25 Gender: FEMALE EMail: jane.doe@example.com Phone: 202-123-4678 Address: 33 3rd St, Smallville, KS 12333 Name: John Doe Age: 25 Gender: MALE EMail: john.doe@example.com Phone: 202-123-4678 Address: 33 3rd St, Smallville, KS 12333 Name: James Johnson Age: 45 Gender: MALE EMail: james.johnson@example.com Phone: 333-456-1233 Address: 201 2nd St, New York, NY 12111 Name: Joe Bailey Age: 67 Gender: MALE EMail: joebob.bailey@example.com Phone: 112-111-1111 Address: 111 1st St, Town, CA 11111 Name: Phil Smith Age: 55 Gender: MALE EMail: phil.smith@examp;e.com Phone: 222-33-1234 Address: 22 2nd St, New Park, CO 222333 Name: Betty Jones Age: 85 Gender: FEMALE EMail: betty.jones@example.com Phone: 211-33-1234 Address: 22 4th St, New Park, CO 222333 ===Eastern List=== Name: Baker Bob Age: 21 Gender: MALE EMail: bob.baker@example.com Phone: 201-121-4678 Address: 44 4th St, Smallville, KS 12333 Name: Doe Jane Age: 25 Gender: FEMALE EMail: jane.doe@example.com Phone: 202-123-4678 Address: 33 3rd St, Smallville, KS 12333 Name: Doe John Age: 25 Gender: MALE EMail: john.doe@example.com Phone: 202-123-4678 Address: 33 3rd St, Smallville, KS 12333 Name: Johnson James Age: 45 Gender: MALE EMail: james.johnson@example.com Phone: 333-456-1233 Address: 201 2nd St, New York, NY 12111 Name: Bailey Joe Age: 67 Gender: MALE EMail: joebob.bailey@example.com Phone: 112-111-1111 Address: 111 1st St, Town, CA 11111 Name: Smith Phil Age: 55 Gender: MALE EMail: phil.smith@examp;e.com Phone: 222-33-1234 Address: 22 2nd St, New Park, CO 222333 Name: Jones Betty Age: 85 Gender: FEMALE EMail: betty.jones@example.com Phone: 211-33-1234 Address: 22 4th St, New Park, CO 222333
lambda表达式和集合 体验过Function接口的优点还没完,java 8给我们的惊喜还不止这些。(不这些都不够,我必须是你近旁的一只木棉,根紧握地里,也相触云间 … 神特么的乱入),lambda基础部分结束后,来看看在集合方面它又有哪些优势。
先看看有哪些不一样的操作符:
forEach
stream
filter
collection
map
1.添加新的类,将查询条件全部封装进HashMap中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class SearchCriteria { private final Map<String, MyTest<Person>> searchMap = new HashMap<>(); private SearchCriteria() { super(); initSearchMap(); } private void initSearchMap() { MyTest<Person> allDrivers = p -> p.getAge() >= 16; MyTest<Person> allDraftees = p -> p.getAge() >= 18 && p.getAge() <= 25 && p.getGender() == Gender.MALE; MyTest<Person> allPilots = p -> p.getAge() >= 23 && p.getAge() <= 65; searchMap.put("allDrivers", allDrivers); searchMap.put("allDraftees", allDraftees); searchMap.put("allPilots", allPilots); } public MyTest<Person> getCriteria(String PredicateName) { MyTest<Person> target; target = searchMap.get(PredicateName); if (target == null) { System.out.println("Search Criteria not found... "); System.exit(1); } return target; } public static SearchCriteria getInstance() { return new SearchCriteria(); } }
2.Looping
Test01ForEach.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static void main(String[] args) { List<Person> pl = Person.createShortList(); System.out.println("\n=== Western Phone List ==="); pl.forEach(p -> p.printWesternName()); System.out.println("\n=== Eastern Phone List ==="); pl.forEach(Person::printEasternName); System.out.println("\n=== Custom Phone List ==="); pl.forEach(p -> { System.out.println(p.printCustom(r -> "Name: " + r.getGivenName() + " EMail: " + r.getEmail())); }); }
3.链式调用和过滤器
Test02Filter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Test02Filter { public static void main(String[] args) { List<Person> pl = Person.createShortList(); SearchCriteria search = SearchCriteria.getInstance(); System.out.println("\n=== Western Pilot Phone List ==="); pl.stream().filter(search.getCriteria("allPilots")) .forEach(Person::printWesternName); System.out.println("\n=== Eastern Draftee Phone List ==="); pl.stream().filter(search.getCriteria("allDraftees")) .forEach(Person::printEasternName); } }
4.getting Lazy
由于篇幅过长,写的有点疲惫,细枝末节的地方,可能没描述清楚,留言里面见;当然这个getting lazy说的并不是我懒
Laziness:跟java-web的懒加载类似的概念,在前面程序中,循环就采取了了‘lazy’的方式,在filter之后再进行输出,这是一种更为高效的方式
Eagerness:Code that performs operations on every object in a list is considered “eager”. For example, an enhanced for loop that iterates through an entire list to process two objects, is considered a more “eager” approach.(ps : 直接给原文了)
stream 在上面的代码中,filter之前都会先使用stream,stream方法会将Collection作为输入,返回java.util.stream.Stream接口作为输出。Stream就是集合中元素的序列;默认情况下,一旦元素被调用在stream中将不再有该元素,类似于java中的queuen,因此,每个stream只能被使用一次;另外,stream能变成一个序列在该方法调用之后,后文的例子将印证这一点。
转化和结果
当stream被使用之后被处理,所以在stream中的元素,是无法发生更改;那么如果你还是想在链式操作之后保留stream对应的collection:可以将他们保留在一个新的集合中SHOW CODE :
Test03toList.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Test03toList { public static void main(String[] args) { List<Person> pl = Person.createShortList(); SearchCriteria search = SearchCriteria.getInstance(); // Make a new list after filtering. List<Person> pilotList = pl .stream() .filter(search.getCriteria("allPilots")) .collect(Collectors.toList()); System.out.println("\n=== Western Pilot Phone List ==="); pilotList.forEach(Person::printWesternName); } } .collect(Collectors.toList()); 返回一个新的collection
集合中的计算
map()通常和filter成对出现,map会从对象里抽出某个属性,来执行一些操作,下面的例子以age作为主要的操作字段,来呈现集合中计算的用法
Test04Map.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class Test04Map { public static void main(String[] args) { List<Person> pl = Person.createShortList(); SearchCriteria search = SearchCriteria.getInstance(); // Calc average age of pilots old style System.out.println("== Calc Old Style =="); int sum = 0; int count = 0; for (Person p:pl){ if (p.getAge() >= 23 && p.getAge() <= 65 ){ sum = sum + p.getAge(); count++; } } long average = sum / count; System.out.println("Total Ages: " + sum); System.out.println("Average Age: " + average); // Get sum of ages System.out.println("\n== Calc New Style =="); long totalAge = pl .stream() .filter(search.getCriteria("allPilots")) .mapToInt(p -> p.getAge()) .sum(); // Get average of ages OptionalDouble averageAge = pl .parallelStream() .filter(search.getCriteria("allPilots")) .mapToDouble(p -> p.getAge()) .average(); System.out.println("Total Ages: " + totalAge); System.out.println("Average Age: " + averageAge.getAsDouble()); } }
结语 总算是写完了,博客后面写得不是很走心,但是还是比较开心,又一次通过官方文档,完成了一个知识点:另外由于篇幅问题,Android Studio中如何引入java 8将在另外一篇博客中说明,lambda就到这里了,欢迎勘误。
参考文档 oracle 官方教程