小言_互联网的博客

lambda表达式

272人阅读  评论(0)

1. Lambda表达式

1.1 Lambda使用场景

       Lambda表达式是java8引入的新特性,直接点说,就是新的一种java语法,是每一个java程序猿必须掌握的技能。它的使用场景是,当我需要实现一个被@FunctionalInterface注解修饰的接口时,我们就可以使用Lambda表达式。比如我们需要一个实现了Runnable接口的类,或需要一个实现了Comparator接口的类,再或者我们自定义了一个接口(接口被@FunctionalInterface注解),当我们需要这个接口的实现类的时候,也可以直接使用lambda表达式。

@FunctionalInterface注解的作用是,告诉jvm,这个接口是只包含一个方法的接口。所以,我们编写的lambda表达式就是对这个接口仅有的一个方法的实现!只要被这个注解修饰的接口,我们就称它为函数式接口。从目前的经验看,lambda表达式实现这个接口方法的时候,是无法像一个正常的接口实现类那样还能新增实现类的属性,或者新增其他方法等。如果想让实现类具备自己的属性,或者定义其他方法,那还是按照原来的写法,去实现这个接口吧。


  
  1. @FunctionalInterface
  2. public interface Runnable {
  3. public abstract void run();
  4. }

     使用Lambda创建一个Runnable的实现类,来执行一个线程,代码如下


  
  1. public void test1(){
  2. //jdk 1.7 前,必须是 final
  3. int num = 0;
  4. // 使用匿名内部类的方式
  5. Runnable r = new Runnable() {
  6. @Override
  7. public void run() {
  8. System.out.println( "Hello World!" + num);
  9. }
  10. };
  11. r.run();
  12. System.out.println( "分割线-------------------------------");
  13. // 使用lambda 一行代码实现Runnable接口的run方法
  14. Runnable r1 = () -> System.out.println( "Hello Lambda!");
  15. r1.run();
  16. }

1.2 Lambda基础语法

Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符:箭头操作符将 Lambda 表达式拆分成两部分:

左侧:Lambda 表达式的参数列表

右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体

  • 语法格式一:实现的接口方法无参数,无返回值

       Runnable r1 = () -> System.out.println("Hello Lambda!");

  • 语法格式二:实现的接口方法有一个参数,并且无返回值

        (x) -> System.out.println(x);  //x是随便起的名字,想叫什么都行

  • 语法格式三:实现的接口方法若只有一个参数,小括号可以省略不写

        x -> System.out.println(x)

  • 语法格式四:实现的接口方法有两个以上的参数,有返回值,并且 Lambda 体中有多条语句

       Comparator<Integer> com = (x, y) -> {

            System.out.println("函数式接口");

           return Integer.compare(x, y);

        };

      // lambda表达式需要多条语句,那就用{},有返回值则最后使用return

  • 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

       Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

  • 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”

       (Integer x, Integer y) -> Integer.compare(x, y);

通过上面的语法总结,只要我们需要一个函数式接口的实现类的简单实现时,就可以直接使用lambda表达式,来表示这个实现类。

1.3 Java8 内置的四大核心函数式接口

通过上面的学习,我们知道写lambda之前必须先有一个函数式接口,那么java8就为我们提供了四大核心函数式接口。

  1. Consumer<T> : 消费型接口  void accept(T t);
  2. Supplier<T> : 供给型接口    T get();
  3. Function<T, R> : 函数型接口   R apply(T t);
  4. Predicate<T> : 断言型接口    boolean test(T t);

  
  1. package com.wqh.demo.java8;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.List;
  5. import java.util.function.Consumer;
  6. import java.util.function.Function;
  7. import java.util.function.Predicate;
  8. import java.util.function.Supplier;
  9. import org.junit.Test;
  10. /*
  11. * Java8 内置的四大核心函数式接口
  12. *
  13. * Consumer<T> : 消费型接口
  14. * void accept(T t);
  15. *
  16. * Supplier<T> : 供给型接口
  17. * T get();
  18. *
  19. * Function<T, R> : 函数型接口
  20. * R apply(T t);
  21. *
  22. * Predicate<T> : 断言型接口
  23. * boolean test(T t);
  24. *
  25. */
  26. public class TestLambda3 {
  27. //Predicate<T> 断言型接口:
  28. @Test
  29. public void test4(){
  30. List<String> list = Arrays.asList( "Hello", "atguigu", "Lambda", "www", "ok");
  31. List<String> strList = filterStr(list, (s) -> s.length() > 3);
  32. for (String str : strList) {
  33. System.out.println(str);
  34. }
  35. }
  36. //需求:将满足条件的字符串,放入集合中
  37. public List<String> filterStr(List<String> list, Predicate<String> pre){
  38. List<String> strList = new ArrayList<>();
  39. for (String str : list) {
  40. if(pre.test(str)){
  41. strList.add(str);
  42. }
  43. }
  44. return strList;
  45. }
  46. //Function<T, R> 函数型接口:
  47. @Test
  48. public void test3(){
  49. String newStr = strHandler( "\t\t\t 我大中华威武 ", (str) -> str.trim());
  50. System.out.println(newStr);
  51. String subStr = strHandler( "我大中华威武", (str) -> str.substring( 2, 5));
  52. System.out.println(subStr);
  53. }
  54. //需求:用于处理字符串
  55. public String strHandler(String str, Function<String, String> fun){
  56. return fun.apply(str);
  57. }
  58. //Supplier<T> 供给型接口 :
  59. @Test
  60. public void test2(){
  61. List<Integer> numList = getNumList( 10, () -> ( int)(Math.random() * 100));
  62. for (Integer num : numList) {
  63. System.out.println(num);
  64. }
  65. }
  66. //需求:产生指定个数的整数,并放入集合中
  67. public List<Integer> getNumList(int num, Supplier<Integer> sup){
  68. List<Integer> list = new ArrayList<>();
  69. for ( int i = 0; i < num; i++) {
  70. Integer n = sup.get();
  71. list.add(n);
  72. }
  73. return list;
  74. }
  75. //Consumer<T> 消费型接口 :
  76. @Test
  77. public void test1(){
  78. happy( 10000, (m) -> System.out.println( "你们刚哥喜欢大宝剑,每次消费:" + m + "元"));
  79. }
  80. public void happy(double money, Consumer<Double> con){
  81. con.accept(money);
  82. }
  83. }

1.4 Lambda方法引用

一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)

1. 对象的引用 :: 实例方法名

2. 类名 :: 静态方法名

3. 类名 :: 实例方法名

注意:

 ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!

 ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName


  
  1. //对象的引用 :: 实例方法名
  2. @Test
  3. public void test2(){
  4. Employee emp = new Employee( 101, "张三", 18, 9999.99);
  5. Supplier<String> sup = () -> emp.getName();
  6. System.out.println(sup.get());
  7. System.out.println( "----------------------------------");
  8. // getName方法与Supplier接口的get方法,入参相同、返回值类型相同
  9. Supplier<String> sup2 = emp::getName;
  10. System.out.println(sup2.get());
  11. }
  12. //类名 :: 静态方法名
  13. @Test
  14. public void test3(){
  15. BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
  16. System.out.println(fun.apply( 1.5, 22.2));
  17. System.out.println( "--------------------------------------------------");
  18. // BiFunction的apply方法,同Math的max方法,入参类型相同,返回值类型相同,可以直接忽略的参数列表
  19. BiFunction<Double, Double, Double> fun2 = Math::max;
  20. System.out.println(fun2.apply( 1.2, 1.5));
  21. }
  22. //类名 :: 实例方法名
  23. @Test
  24. public void test5(){
  25. // BiPredicate接口的boolean test(T t, U u)方法
  26. BiPredicate<String, String> bp = (x, y) -> x.equals(y);
  27. System.out.println(bp.test( "abcde", "abcde"));
  28. System.out.println( "-----------------------------------------");
  29. // 使用第一个参数调用equals方法,将第二个参数作为equals的入参
  30. BiPredicate<String, String> bp2 = String::equals;
  31. System.out.println(bp2.test( "abc", "abc"));
  32. System.out.println( "-----------------------------------------");
  33. // Function接口的R apply(T t)方法
  34. Function<Employee, String> fun = (e) -> e.show();
  35. System.out.println(fun.apply( new Employee()));
  36. System.out.println( "-----------------------------------------");
  37. // 使用第一个参数一个Employee对象调用show方法
  38. Function<Employee, String> fun2 = Employee::show;
  39. System.out.println(fun2.apply( new Employee()));
  40. }
  41. //类名 :: 实例方法名
  42. @Test
  43. public void test5(){
  44. // BiPredicate接口的boolean test(T t, U u)方法
  45. BiPredicate<String, String> bp = (x, y) -> x.equals(y);
  46. System.out.println(bp.test( "abcde", "abcde"));
  47. System.out.println( "-----------------------------------------");
  48. // 使用第一个参数调用equals方法,将第二个参数作为equals的入参
  49. BiPredicate<String, String> bp2 = String::equals;
  50. System.out.println(bp2.test( "abc", "abc"));
  51. System.out.println( "-----------------------------------------");
  52. // Function接口的R apply(T t)方法
  53. Function<Employee, String> fun = (e) -> e.show();
  54. System.out.println(fun.apply( new Employee()));
  55. System.out.println( "-----------------------------------------");
  56. // 使用第一个参数一个Employee对象调用show方法
  57. Function<Employee, String> fun2 = Employee::show;
  58. System.out.println(fun2.apply( new Employee()));
  59. }

二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!

1. 类名 :: new

2. 数组引用 类型[] :: new;


  
  1. @Test
  2. public void test6(){
  3. //Supplier接口的T get();方法
  4. Supplier<Employee> sup = () -> new Employee();
  5. System.out.println(sup.get());
  6. System.out.println( "------------------------------------");
  7. //自动匹配Employee的无参构造器
  8. Supplier<Employee> sup2 = Employee:: new;
  9. System.out.println(sup2.get());
  10. //BiFunction的R apply(T t, U u);方法,自动匹配参数类型是String, Integer的构造器
  11. BiFunction<String, Integer, Employee> fun2 = Employee:: new;
  12. System.out.println(fun2.apply( "小明", 28));
  13. }
  14. //数组引用
  15. @Test
  16. public void test8(){
  17. Function<Integer, String[]> fun = (args) -> new String[args];
  18. String[] strs = fun.apply( 10);
  19. System.out.println(strs.length);
  20. System.out.println( "--------------------------");
  21. Function<Integer, Employee[]> fun2 = Employee[] :: new;
  22. Employee[] emps = fun2.apply( 20);
  23. System.out.println(emps.length);
  24. }

 


  
  1. package com.wqh.demo.java8;
  2. public class Employee {
  3. private int id;
  4. private String name;
  5. private int age;
  6. private double salary;
  7. private Status status;
  8. public Employee() {
  9. }
  10. public Employee(String name) {
  11. this.name = name;
  12. }
  13. public Employee(String name, int age) {
  14. this.name = name;
  15. this.age = age;
  16. }
  17. public Employee(int id, String name, int age, double salary) {
  18. this.id = id;
  19. this.name = name;
  20. this.age = age;
  21. this.salary = salary;
  22. }
  23. public Employee(int id, String name, int age, double salary, Status status) {
  24. this.id = id;
  25. this.name = name;
  26. this.age = age;
  27. this.salary = salary;
  28. this.status = status;
  29. }
  30. public Status getStatus() {
  31. return status;
  32. }
  33. public void setStatus(Status status) {
  34. this.status = status;
  35. }
  36. public int getId() {
  37. return id;
  38. }
  39. public void setId(int id) {
  40. this.id = id;
  41. }
  42. public String getName() {
  43. return name;
  44. }
  45. public void setName(String name) {
  46. this.name = name;
  47. }
  48. public int getAge() {
  49. return age;
  50. }
  51. public void setAge(int age) {
  52. this.age = age;
  53. }
  54. public double getSalary() {
  55. return salary;
  56. }
  57. public void setSalary(double salary) {
  58. this.salary = salary;
  59. }
  60. public String show() {
  61. return "测试方法引用!";
  62. }
  63. @Override
  64. public int hashCode() {
  65. final int prime = 31;
  66. int result = 1;
  67. result = prime * result + age;
  68. result = prime * result + id;
  69. result = prime * result + ((name == null) ? 0 : name.hashCode());
  70. long temp;
  71. temp = Double.doubleToLongBits(salary);
  72. result = prime * result + ( int) (temp ^ (temp >>> 32));
  73. return result;
  74. }
  75. @Override
  76. public boolean equals(Object obj) {
  77. if ( this == obj)
  78. return true;
  79. if (obj == null)
  80. return false;
  81. if (getClass() != obj.getClass())
  82. return false;
  83. Employee other = (Employee) obj;
  84. if (age != other.age)
  85. return false;
  86. if (id != other.id)
  87. return false;
  88. if (name == null) {
  89. if (other.name != null)
  90. return false;
  91. } else if (!name.equals(other.name))
  92. return false;
  93. if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
  94. return false;
  95. return true;
  96. }
  97. @Override
  98. public String toString() {
  99. return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status
  100. + "]";
  101. }
  102. public enum Status {
  103. FREE, BUSY, VOCATION;
  104. }
  105. }

转载:https://blog.csdn.net/u010327957/article/details/104777717
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场