@boothsun
2018-05-05T06:57:44.000000Z
字数 7535
阅读 1701
Java
参考原文地址:
1. Java Lambda表达式入门
2. java8 手把手教你学会写lambda表达式
Lambda是一个匿名函数,我们可以把lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),可以写出更简单、更灵活的代码。但是,需要注意,Lambda表达式的本质只是一个“语法糖”,是由编译器推断并帮你转换包装为常规的代码,因此你才可以使用更少的代码来实现同样的功能。
(parameters) -> expression(parameters) -> { statements; }
// 语法格式一:无参,无返回值,Lambda体只需一条语句Runnable r1 = () -> System.out.println("Hello Lambda");// 语法格式二:Lambda需要一个参数Consumer<String> consumer = (args) -> System.out.println(args) ;// 语法格式三: Lambda只需要一个参数时,参数的小括号可以省略Consumer<String> consumer = args -> System.out.println(args) ;// 语法格式四:Lambda需要两个参数,并且有返回值BinaryOperator<Long> bo = (x,y) -> {return x + y ;};// 语法格式五:当Lambda体只有一条语句时,return与大括号都可以省略BinaryOperator<Long> bo = (x,y) -> x + y;// 语法格式六:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”BinaryOperator<Long> bo = (Long x,Long y) -> x + y;
// 对集合进行遍历List<String> languages = Arrays.asList("java","scala","python");languages.forEach(x -> System.out.println(x));languages.forEach(System.out::println);// 对集合进行排序Integer[] itArray = {3,0,9,8,1,32};Arrays.sort(itArray, (o1, o2) -> o1.compareTo(o2));
个人理解,这种场景也可以归属到匿名内部类的使用场景。
@FunctionalInterface注解,这样做可以检查它是否是一个函数接口,同时JavaDoc也会包含一条声明,说明这个接口是一个函数式接口。
// 自定义函数式接口@FunctionalInterfaceinterface MyNumber {double getValue() ;}// 自定义函数式接口中使用泛型@FunctionalInterfaceinterface MyFunc<T> {T getValue(T t);}// 使用自定义函数接口@Testpublic void test3() {String str = toUpperString((t) -> t.toUpperCase(),"www");System.out.println(str);}public String toUpperString(MyFunc<String> mf , String str) {return mf.getValue(str) ;}
四个核心接口:

其他接口

Stream是对集合的包装,这里主要讲Lambda,所以对Stream的语法使用不进行任何讲解。
操作Map集合
List<Double> cost = Arrays.asList(10.0, 20.0,30.0);cost.stream().map(x -> x + x * 0.05).forEach(System.out::println);
操作List集合
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()));
我们也可以定义过滤器,然后重用它们来执行其他操作:
// 定义 filtersPredicate<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()));// 重用filtersSystem.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:
//计算 count, min, max, sum, and average for numbersList<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());
个人对Lambda的认知就是:匿名内部类。