java8新特性学习

lambda

在学习lambda之前先来看一段代码,传入一个User的集合,返回符合条件的User集合

  public static List<User> filter(List<User> users, Predicate<User> predicate) {
    List<User> result = new ArrayList<>();
    for (User user: users){
      if (predicate.test(user)) result.add(user);
    }
    return result;
  }

代码中使用了Predicate接口, 接受一个泛型T,返回一个布尔值

  @FunctionalInterface
  public interface Predicate<T> {
    boolean test(T t);
  }

java7中,我们可以使用匿名内部类来作为入参来调用filter方法

  public static List<User> filterZhang(List<User> users) {
    return filter(users, new Predicate<User>() {
      @Override
      public boolean test(User user) {
        return user.getName().startsWith("张");
      }
    });
  }

java8中,我们可以使用lambda来实现

  public static List<User> filterWang(List<User> users) {
    return filter(users, user -> user.getName().startsWith("王"));
  }

lambda其实是一个箭头函数,也可称为匿名函数,类似于ES6中的箭头函数,只不过javascript中使用=>, 而java中使用->

lambda的语法

箭头操作符将lambda表达式分成了两部分:

  • 左侧:lambda表达式的参数列表(接口中抽象方法的参数列表)
  • 右侧:lambda表达式中所需执行的功能(lambda体,对抽象方法的实现)

上面说到的抽象方法,指的就是Predicate接口中唯一的一个抽象方法 test,接收一个泛型T,返回boolean值

boolean test(T t)

再看看我们写的lambda表达式, 是不是接受一个泛型为User的user对象,如果user的姓王就返回true,反之返回false, 参数和返回值 一一对应

user -> user.getName().startsWith("王")

所以 lambda箭头函数必须和Predicate接口中那个唯一的抽象方法保持一致(参数和返回值完全相同),正因为如此,lambda中会对参数类型进行类型推断, 我们只写了一个user, java就知道这是一个User对象

语法有如下几种格式:

  • 语法格式一(无参数无返回值):
() -> 具体实现
  • 语法格式二(有一个参数无返回值):
(x) -> 具体实现 
//或 
x -> 具体实现
  • 语法格式三(有多个参数,有返回值,并且lambda体中有多条语句):
(x,y) -> {具体实现}
  • 语法格式四:若方法体只有一条语句,那么大括号和return都可以省略

注:lambda表达式的参数列表的参数类型可以省略不写,可以进行类型推断

函数式接口

什么是函数式接口?
  • 像Runnable和Comparator这样只有一个抽象方法的接口,称为函数式接口。 也可以在接口上加上@FunctionalInterface注解,如果编译通过,则该接口就是函数式接口。
  • lambda表达式就是对函数式接口中那个唯一的抽象方法的实现
函数是接口都有哪些?

函数式接口大部分定义在 java.util.function包中, 且用@FunctionalInterface注解
在这里插入图片描述

看一个需求

需求:需要对两个数进行加减乘除等运算,怎么实现?

  • 传统做法:传统做法中,需要进行几种运算,我们就要写几个方法。一种运算对应一个方法。
public static void main(String[] args) {
    add(2,1);
    minus(2,1);
    multiply(2,1);
    divide(2,1);
  }
  
  static int add(int left, int right) {
    return left + right;
  }

  static int minus(int left, int right) {
    return left - right;
  }
  static int multiply(int left, int right) {
    return left * right;
  }

  static int divide(int left, int right) {
    return left / right;
  }

lambda做法:首先要定义一个函数式接口,接口中只有一个方法,接收两个参数。


public static void main(String[] args) {
    calc(2, 1, (left, right) -> left + right);
    calc(2, 1, (left, right) -> left - right);
    calc(2, 1, (left, right) -> left * right);
    calc(2, 1, (left, right) -> left / right);
  }

  static int calc(int left, int right, Calculate calculate) {
    return calculate.applyAsInt(left, right);
  }

  @FunctionalInterface
  interface Calculate {
    int applyAsInt(int left, int right);
  }
d

所以用lambda的话,只需要定义一个函数式接口,不管进行什么操作,都可以用lambda解决,不用再一种运算对应一个方法。但是,还需要自己定义函数式接口,好像也没简单很多。Java考虑到这点了,所以内置了函数式接口, 大部分放在java.util.function包中, 接口用@FunctionalInterface注解。

如Predicate接口
在这里插入图片描述

方法引用

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
  • 如果某个方法和 函数式接口中那个唯一的抽象函数保持一致(参数和返回值), 则可以使用双引号 :: 的方式
  • 不过实现抽象方法的参数列表,必须与引用方法的参数列表保持一致。
方法引用语法:
  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法

在将lambda时举的例子,可以换成方法引用的写法

  public static List<User> filterLi(List<User> users) {
    return filter(users, Demo1::test);
  }
  // test 相当于 Predicat接口中抽象方法test的实现
  private static boolean test(User user) {
    return user.getName().startsWith("李");
  }

方法引用相较于lambda表达式的优点

  • 有自己的方法名,要干什么一目了然
  • 因为是一个方法,所以可以有复杂的逻辑代码,而在lambda中写复杂的逻辑代码是很不优雅的, 可读性变差

(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值