[关闭]
@boothsun 2018-05-05T14:57:44.000000Z 字数 7535 阅读 1471

JDK1.8 Lambda表达式使用

Java


参考原文地址:
1. Java Lambda表达式入门
2. java8 手把手教你学会写lambda表达式

Lambda表达式的作用

Lambda是一个匿名函数,我们可以把lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),可以写出更简单、更灵活的代码。但是,需要注意,Lambda表达式的本质只是一个“语法糖”,是由编译器推断并帮你转换包装为常规的代码,因此你才可以使用更少的代码来实现同样的功能。

Lambda表达式基本语法结构

  1. (parameters) -> expression
  2. (parameters) -> { statements; }

代替匿名内部类

  1. // 语法格式一:无参,无返回值,Lambda体只需一条语句
  2. Runnable r1 = () -> System.out.println("Hello Lambda");
  3. // 语法格式二:Lambda需要一个参数
  4. Consumer<String> consumer = (args) -> System.out.println(args) ;
  5. // 语法格式三: Lambda只需要一个参数时,参数的小括号可以省略
  6. Consumer<String> consumer = args -> System.out.println(args) ;
  7. // 语法格式四:Lambda需要两个参数,并且有返回值
  8. BinaryOperator<Long> bo = (x,y) -> {
  9. return x + y ;
  10. };
  11. // 语法格式五:当Lambda体只有一条语句时,return与大括号都可以省略
  12. BinaryOperator<Long> bo = (x,y) -> x + y;
  13. // 语法格式六:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
  14. BinaryOperator<Long> bo = (Long x,Long y) -> x + y;

运用到集合中

  1. // 对集合进行遍历
  2. List<String> languages = Arrays.asList("java","scala","python");
  3. languages.forEach(x -> System.out.println(x));
  4. languages.forEach(System.out::println);
  5. // 对集合进行排序
  6. Integer[] itArray = {3,0,9,8,1,32};
  7. Arrays.sort(itArray, (o1, o2) -> o1.compareTo(o2));

个人理解,这种场景也可以归属到匿名内部类的使用场景。

与函数式接口的结合使用

自定义函数式接口

  1. // 自定义函数式接口
  2. @FunctionalInterface
  3. interface MyNumber {
  4. double getValue() ;
  5. }
  6. // 自定义函数式接口中使用泛型
  7. @FunctionalInterface
  8. interface MyFunc<T> {
  9. T getValue(T t);
  10. }
  11. // 使用自定义函数接口
  12. @Test
  13. public void test3() {
  14. String str = toUpperString((t) -> t.toUpperCase(),"www");
  15. System.out.println(str);
  16. }
  17. public String toUpperString(MyFunc<String> mf , String str) {
  18. return mf.getValue(str) ;
  19. }

Java内置的函数式接口

  1. 四个核心接口:
    image.png-113.1kB

  2. 其他接口
    image.png-155.9kB

Lambda与Stream的结合使用

Stream是对集合的包装,这里主要讲Lambda,所以对Stream的语法使用不进行任何讲解。

  1. 操作Map集合

    1. List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
    2. cost.stream().map(x -> x + x * 0.05).forEach(System.out::println);
  2. 操作List集合

    1. public class Person {
    2. private String firstName, lastName, job, gender;
    3. private int salary, age;
    4. public Person(String firstName, String lastName, String job,
    5. String gender, int age, int salary) {
    6. this.firstName = firstName;
    7. this.lastName = lastName;
    8. this.gender = gender;
    9. this.age = age;
    10. this.job = job;
    11. this.salary = salary;
    12. }
    13. // Getter and Setter
    14. // . . . . .
    15. }

    接下来,我们将创建两个list,都用来存放Person对象:

    1. List<Person> javaProgrammers = new ArrayList<Person>() {
    2. {
    3. add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000));
    4. add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500));
    5. add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800));
    6. add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600));
    7. add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200));
    8. add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900));
    9. add(new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300));
    10. add(new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700));
    11. add(new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000));
    12. add(new Person("Addison", "Pam", "Java programmer", "female", 34, 1300));
    13. }
    14. };
    15. List<Person> phpProgrammers = new ArrayList<Person>() {
    16. {
    17. add(new Person("Jarrod", "Pace", "PHP programmer", "male", 34, 1550));
    18. add(new Person("Clarette", "Cicely", "PHP programmer", "female", 23, 1200));
    19. add(new Person("Victor", "Channing", "PHP programmer", "male", 32, 1600));
    20. add(new Person("Tori", "Sheryl", "PHP programmer", "female", 21, 1000));
    21. add(new Person("Osborne", "Shad", "PHP programmer", "male", 32, 1100));
    22. add(new Person("Rosalind", "Layla", "PHP programmer", "female", 25, 1300));
    23. add(new Person("Fraser", "Hewie", "PHP programmer", "male", 36, 1100));
    24. add(new Person("Quinn", "Tamara", "PHP programmer", "female", 21, 1000));
    25. add(new Person("Alvin", "Lance", "PHP programmer", "male", 38, 1600));
    26. add(new Person("Evonne", "Shari", "PHP programmer", "female", 40, 1800));
    27. }
    28. };

    现在我们使用forEach方法来迭代输出上述列表:

    1. System.out.println("所有程序员的姓名:");
    2. javaProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(),p.getLastName()));
    3. phpProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

    我们同样使用forEach方法,增加程序员的工资5%:

    1. System.out.println("给程序员加薪 5% :");
    2. Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());
    3. javaProgrammers.forEach(giveRaise);
    4. phpProgrammers.forEach(giveRaise);

    另一个有用的方法是过滤器filter(),让我们显示月薪超过1400美元的PHP程序员:

    1. System.out.println("下面是月薪超过 $1,400 的PHP程序员:")
    2. phpProgrammers.stream()
    3. .filter((p) -> (p.getSalary() > 1400))
    4. .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

    我们也可以定义过滤器,然后重用它们来执行其他操作:

    1. // 定义 filters
    2. Predicate<Person> ageFilter = (p) -> (p.getAge() > 25);
    3. Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400);
    4. Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender()));
    5. System.out.println("下面是年龄大于 24岁且月薪在$1,400以上的女PHP程序员:");
    6. phpProgrammers.stream()
    7. .filter(ageFilter)
    8. .filter(salaryFilter)
    9. .filter(genderFilter)
    10. .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
    11. // 重用filters
    12. System.out.println("年龄大于 24岁的女性 Java programmers:");
    13. javaProgrammers.stream()
    14. .filter(ageFilter)
    15. .filter(genderFilter)
    16. .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

    使用limit方法,可以限制结果集的个数:

    1. System.out.println("最前面的3个 Java programmers:");
    2. javaProgrammers.stream()
    3. .limit(3)
    4. .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
    5. System.out.println("最前面的3个女性 Java programmers:");
    6. javaProgrammers.stream()
    7. .filter(genderFilter)
    8. .limit(3)
    9. .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

    排序呢? 我们在stream中能处理吗? 答案是肯定的。 在下面的例子中,我们将根据名字和薪水排序Java程序员,放到一个list中,然后显示列表:

    1. System.out.println("根据 name 排序,并显示前5个 Java programmers:");
    2. List<Person> sortedJavaProgrammers = javaProgrammers
    3. .stream()
    4. .sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName())))
    5. .limit(5)
    6. .collect(toList());
    7. sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));
    8. System.out.println("根据 salary 排序 Java programmers:");
    9. sortedJavaProgrammers = javaProgrammers
    10. .stream()
    11. .sorted( (p, p2) -> (p.getSalary() - p2.getSalary()) )
    12. .collect( toList() );
    13. sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));

    如果我们只对最低和最高的薪水感兴趣,比排序后选择第一个/最后一个 更快的是min和max方法:

    1. System.out.println("工资最低的 Java programmer:");
    2. Person pers = javaProgrammers
    3. .stream()
    4. .min((p1, p2) -> (p1.getSalary() - p2.getSalary()))
    5. .get()
    6. System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary())
    7. System.out.println("工资最高的 Java programmer:");
    8. Person person = javaProgrammers
    9. .stream()
    10. .max((p, p2) -> (p.getSalary() - p2.getSalary()))
    11. .get()
    12. System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())

    上面的例子中我们已经看到collect方法是如何工作的。结合map方法,我们可以使用collect方法来将我们的结果集放到一个字符串,一个 Set 或一个TreeSet中:

    1. System.out.println("将 PHP programmers 的 first name 拼接成字符串:");
    2. String phpDevelopers = phpProgrammers
    3. .stream()
    4. .map(Person::getFirstName)
    5. .collect(joining(" ; ")); // 在进一步的操作中可以作为标记(token)
    6. System.out.println("将 Java programmers 的 first name 存放到 Set:");
    7. Set<String> javaDevFirstName = javaProgrammers
    8. .stream()
    9. .map(Person::getFirstName)
    10. .collect(toSet());
    11. System.out.println("将 Java programmers 的 first name 存放到 TreeSet:");
    12. TreeSet<String> javaDevLastName = javaProgrammers
    13. .stream()
    14. .map(Person::getLastName)
    15. .collect(toCollection(TreeSet::new));

    Streams 还可以是并行的(parallel)。 示例如下:

    1. System.out.println("计算付给 Java programmers 的所有money:");
    2. int totalSalary = javaProgrammers
    3. .parallelStream()
    4. .mapToInt(p -> p.getSalary())
    5. .sum();

    我们可以使用summaryStatistics方法获得stream中元素的各种汇总数据。 接下来,我们可以访问这些方法,比如getMaxgetMingetSumgetAverage

    1. //计算 count, min, max, sum, and average for numbers
    2. List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    3. IntSummaryStatistics stats = numbers
    4. .stream()
    5. .mapToInt((x) -> x)
    6. .summaryStatistics();
    7. System.out.println("List中最大的数字 : " + stats.getMax());
    8. System.out.println("List中最小的数字 : " + stats.getMin());
    9. System.out.println("所有数字的总和 : " + stats.getSum());
    10. System.out.println("所有数字的平均值 : " + stats.getAverage());

    总结

    个人对Lambda的认知就是:匿名内部类。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注