Java中使用Lambda表达式

在项目中突然看到同事使用了一种看不懂的语法,以前多行的代码使用这种语法往往一行就能够达到同样的效果。一查资料才知道是Lambda表达式,Java在Version8中引入了该特性。不得不说自己有太久没有主动学习过新的东西,刚好项目忙过,能够抽空学习下Lambda表达式。

下面将由如下几个环节学习Lambda表达式:

  1. Lambda的定义
  2. Lambda的语法
  3. 如何在Java中使用
  4. Java中的内置函数型接口

Lambda定义

想要在Java中使用Lambda表达式,那么我们必须知道Lambda是个什么东西。简单来说,Lambda表达式就是一个匿名函数,也就是没有名称的函数

了解了定义,那么如何书写一个Lambda表达式呢,这时他的语法就粉墨登场了。

Lambda语法

普通语法

(param1,param2,...) -> {
    statement1,
    statement2,
    ...
    return statement3;
}

上面语法定义了Lambda表达式的通用语法,左边括号部分为参数,右边花括号部分为方法体,参数与方法体之间通过->进行分隔。 如果细分又可以分为单参数和多参数:

  1. 单参数:可以省略左边括号,如:
param -> {
    statement1,
    statement2,
    ...
    return statement3;
}

如果方法体只有一行时,甚至可以省略方法体的花括号,如:

param -> statement
  1. 多参数与通用语法一致。

方法引用、构造器引用语法

  • 方法引用
// 实例名称::实例方法
objectName::instanceMethod
// 类名称::静态方法
ClassName::staticMethod
// 类名称::实例方法
ClassName::instanceMethod

方法引用调用者与方法之间使用::进行分隔。

前面两种语法类似,等同于直接把Lambda表达式参数当成instanceMethod/staticMethod参数进行使用,例如:

System.out::println 等同于 s -> System.out.println(s)

Math::max等同于(int x, int y) -> Math.max(x,y)

最后一种为类名称调用实例方法,等同于Lambda表达式把第一个参数作为方法调用者,后面参数作为方法参数进行使用,例如:

Object::equals等同于(o1,o2) -> o1.equals(o2)

  • 构造器引用
ClassName::new

等同于Lambda表达式将参数作为构造器的参数使用,例如: BigDecimal::new等同于x -> new BigDecimal(x)

在Java中的使用

上面了解了Lambda表达式的语法,那么如何在Java中使用呢,下面我们将通过几个例子来进行说明。

  1. 在实际的项目中我们可能会对List进行一个排序,以前我们都是使用如下类似代码进行实现:
List<String> strs = Arrays.asList("1","2","3","4");
strs.sort(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});

而使用Lambda表达式,则代码变成了如下:

strs.sort((s1,s2) -> s1.compareTo(s2));

或者

strs.sort(Comparator.comparing(String::toString));

以前需要5行的代码现在只需要1行,是不是简洁了许多?!

  1. 我们经常会对集合进行遍历,以前的写法是
List<String> strs = Arrays.asList("1","4","2","3");
for (String s : strs){
    System.out.println(s);
}

而使用Lambda表达式,则代码变成了如下

strs.forEach(s -> System.out.println(s));

或者

strs.forEach(System.out::println);

Java中的内置函数型接口

从上面的两个例子可以看出Lambda表达式一般是使用在以匿名类作为参数的方法中,通过传入Lambda表达式对匿名类进行替换。需要注意的是,被替换的匿名类或接口只能有一个方法,这样的接口可以将之称之为函数式接口。同时可以在该接口上添加注解@FunctionalInterface申明该接口为函数式接口。

在Java8中内置了大量的函数式接口供用户使用,下面为大家介绍几个常用的内置接口。

  1. Function<T, R>:函数型接口,接收类型为T的参数,并对其操作,然后返回类型为R的结果。其中包含有apply(T t)方法。

举例:对一个字符串进行截取并返回结果

// 申明方法
public String subStr(String str, Function<String, String> function){
    return function.apply(str);
}
// 调用
subStr("我Code,我快乐", str -> str.substring(0, 2));
  1. Consumer<T>:消费型接口,接收类型为T的参数,对其进行操作。无返回值。其中包含有accept(T t)方法。

举例:打印一句话

// 申明方法
public void print(String s, Consumer<String> consumer){
    consumer.accept(s);
}
// 调用
print("我Code,我快乐", System.out::println);
  1. Supplier<T>:供应型接口,返回类型为T的结果。其中包含有T get()的方法。

举例:获取一个UUID字符串

// 申明方法
static String get(Supplier<String> supplier){
    return supplier.get();
}
// 调用
String uuid = get(() -> UUID.randomUUID().toString());
  1. Predicate<T>:断言型函数,接收类型为T的参数,对其进行断言,返回类型为boolean的结果。其中包含有boolean test(T t)的方法。

举例:判断字符串是否以制定字符开头

// 申明方法
static boolean startWith(String str, Predicate<String> predicate){
    return predicate.test(str);
}
// 调用
boolean result = startWith("I Like Code!", s -> s.startsWith("I"));

Java中内置的常用函数型接口为上述几种,相关接口源码皆可在包java.util.function下进行查看,当然该包下还包含了其他众多函数型接口,有兴趣的可自行查看。

上述就是本篇文章的所有内容,边学习,边总结,最后再输出,这样才能更加有效的加深自己的理解和印象。希望自己在以后的学习中能够坚持。

    原文作者:澎湃
    原文地址: https://zhuanlan.zhihu.com/p/43991759
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞