Java-lambda表达式入门

作者: adm 分类: java 发布时间: 2021-08-09 20:28

Lambda表达式,也可称为闭包,是JDK8的新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以使代码变的更加简洁紧凑。Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。

名字起源是以前还没有计算机时,逻辑学家Alonzo Church想要形式化的表示能有效计算的数学函数,使用了希腊字母lambda( λ \lambda λ)来标记参数,从那以后,带参数变量的表达式就被称为lambda表达式。

lambda表达式本质是一个匿名函数,比如以下函数

1
2
3
public int add(int x, int y) {
    return x + y;
}

可以转换为:

1
(int x, int y) -> x + y;

语法

语法格式如下

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

其中()用来描述参数列表,{}用来描述方法体,->是lambda运算符,读作goes to。

可以包含显示的return语句,如:

1
2
3
4
5
6
(String sirst,String second)->
{
    if(first.length()<second.length())return -1;
    else if(first.length()>second.length())return 1;
    else return 0;
}

可以没有参数,但()不可缺省:
()->{for(int i=0;i<10;i++)System.out.print(i);}

如果可以推导出参数类型,则可以忽略其类型:
Comparator<String>cmp=(first,second)->first.length()-second.length();

特别注意不能只在某些分支返回一个值,这是不合法的,如:
(int x)->{if(x>=0)return 1;}

常用示例:

1
2
3
4
5
6
7
8
9
10
ArrayList<Integer>list=new ArrayList<>();
Collections.addAll(list,1,2,3,4,5);
//遍历
list.forEach(e->{System.out.println(e);});
//删除指定值
list.removeIf(e->e==3);
//排序
list.sort((o1,o2)->o2-o1);
//遍历(双冒号操作符)
list.forEach(System.out::println);

函数式接口

Java中又很多封装代码块的接口,如ActionListenerComparator等,lambda表达式与这些接口时兼容的。
对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式,这种接口称为函数式接口

比如Arrays.sort()方法,它的第二个参数需要一个Comparator实例,而Comparator就是只有一个方法的接口,所以可以使用lambda表达式替代,可以把lambda表达式看作一个函数,而不是一个对象,如:

1
2
Arrays.sort(arrays,
    (first,second)->first.length()-second.length());

lambda表达式还可以转换为接口,比如实现Runnable接口:

1
2
3
new Thread(() -> System.out.println("记得一键三连")).start();
Runnable r = () -> System.out.println("(。・∀・)ノ");
r.run();

再如之前提到的removeIf()方法,它的参数就是一个Predicate接口(位于java.util.function包),这个接口专门用来传递lambda表达式,如删除一个数组列表所有null值:

1
list.removeIf(e->e==null)

方法引用

当在Lambda表达式中直接调用了一个方法时可以使用,其写法为目标引用::方法名称。
有时候,可能已经有现成的方法可以完成你想要传递到其他代码的某个动作,如遍历打印集合:

1
list.forEach(e->{System.out.println(e);});

我们可以直接把现成的println方法传递给它:

1
list.forEach(System.out::println);

它们是等价的,是一个方法引用的写法。
再如对字符串排序而不考虑大小写,可以直接传递以下方法表达式:

1
Arrays.sort(strings,String::compareToIgnoreCase);

也就是说使用双冒号操作符::来分离方法名与对象或类名:

  1. object::instanceMethod
  2. Class::staticMethod
  3. Class::instanceMethod

对于前两种情况,方法引用等价于提供方法参数的lambda表达式,如,Math::Pow等价于(x,y)->Math.pos(x,y)。
对于第三种情况,第一个参数会成为方法的目标,如String::compareToIgnoreCase等同于(x,y)->x.compareToIgnoreCase(y)。

也可以在方法中引用this参数,如this::equals等价于x->this.equals(x),同样的,使用super也是允许的。

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!