java8之lambda表达式用法总结

 更新时间:2020年02月07日 14:46:07   作者:漫夭  
这篇文章主要介绍了java8之lambda表达式用法总结,需要的朋友可以参考下

java8之lambda表达式

目的:行为参数化

Lambda表达式是简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。

Lambda的基本语法是(parameters) -> expression 或 (parameters) -> { statements; }。其中, (parameters) -> expression 的表达式中隐含了return,如 () -> 42; (parameters) -> { statements; } 的花括号内是语句。

举例:

() -> 42  //参数为空,返回一个int
(List<String> list) -> list.isEmpty() //参数为list,返回一个boolean
(int x, int y) -> x*y //参数为两个int,返回一个int
(String s) -> System.out.println(s); //参数为一个String,不返回结果
(String s) -> {System.out.println(s);} //参数为一个String,打印字符串

哪些地方使用哪些lambda

函数式接口是只定义一个抽象方法的接口,即使拥有多个默认方法。FunctionalInterface 标注一个函数式接口,会加入编译检查。函数式接口中默认方法的目的是:改变已发布的接口而不破坏已有的实现。

在接受函数式接口为参数的地方,都可以使用lambda表达式。

例子:

public void execute(Runnable r){
  r.run(); 
}
execute(() -> {}); //使用lambda,Runnable是参数为空,没有返回值的函数式接口,即() -> void 
//fetch返回一个函数式接口,() -> String
public Callable<String> fetch() { 
  return () -> "Tricky example ;-)";
}

为什么只有在函数式接口的地方使用呢?lambda表达式没有函数名,只有参数列表,函数主体和返回值,如果接口有多个方法,就不能直接匹配到正确的方法上了,所以,只有一个抽象方法的函数式接口可以满足。

Predicate

java.util.function.Predicate<T>是一个含有多个默认方法的函数式接口,抽象方法为:(T t) -> bool。看下代码,你就懂了~

FunctionalInterface
public interface Predicate<T> {
  //接口方法,入参为泛型T,返回bool。即:(T t) -> bool
  boolean test(T t);
  //默认方法,and操作
  default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
  }
  //默认方法,取反操作
  default Predicate<T> negate() {
    return (t) -> !test(t);
  }
  //默认方法,or 操作
  default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
  }
  //默认方法,判断是否相等
  static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef)
        ? Objects::isNull
        : object -> targetRef.equals(object);
  }

使用

Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();

Consumer

java.util.function.Consumer<T> 是一个只含有一个默认方法的函数式接口,抽象方法为:(T t) ->void。看下代码,你就懂了~

@FunctionalInterface
public interface Consumer<T> {
  //接口方法,入参为泛型T,返回void。即:(T t) -> void
  void accept(T t);
  //默认方法,可以执行级联操作
  default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
  }

Function

java.util.function.Function<T, R>是一个含有多个默认方法的函数式接口,抽象方法为:(T t) ->R。看下代码,你就懂了~

@FunctionalInterface
public interface Function<T, R> {
  //接口方法,入参为泛型T,返回泛型R。即:(T t) -> R
  R apply(T t);
  //默认方法,实现级联操作。before方法输入V,输出T,本function输入T,输出R。
  default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
  }
  //默认方法,级联操作
  default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
  }
  //默认方法,输入啥,输出啥
  static <T> Function<T, T> identity() {
    return t -> t;
  }

特定方法避免装箱操作

在处理数据时,使用特定方法,可以避免装箱操作,如:IntPredicate、LongConsumer、DoubleFunction等。具体见API库。

总结

函数描述符 函数式接口
(T) ->bool java.util.function.Predicate<T>
(T) -> void java.util.function.Consumer<T>
(T) -> R java.util.function.Function<T, R>
(T,U) -> R java.util.function.BiFunction<T, U, R>
() -> T java.util.function.Supplier<T>

只要函数描述符兼容,函数式接口就可以复用。

特殊的void兼容规则:

// Predicate返回了一个boolean 
Predicate<String> p = s -> list.add(s); 
// Consumer返回了一个void 
Consumer<String> b = s -> list.add(s);

方法引用

方法引用是调用单一方法的Lambda的快捷写法,格式ClassName::methodName。看下栗子你就懂了~

一般方法引用

(Apple a) -> a.getWeight() 等价于Apple::getWeight 
() -> Thread.currentThread().dumpStack() 等价于 Thread.currentThread()::dumpStack
(str, i) -> str.substring(i) 等价于 String::substring
(String s) -> System.out.println(s) 等价于 System.out::println
(list, element) -> list.contains(element) 等价于 List::contains

主要有三类:

  1. 指向静态方法的方法引用,如:Integer::parseInt
  2. 指向任意类型实例方法的方法引用,如:String::length
  3. 指向现有对象的实例方法的方法引用,如:User::getUserId

构造函数引用

无参构造函数

无参构造函数的函数描述符:() -> T,由上面的总结知,可以使用Supplier接口,如下:

Supplier<User> c1 = User::new; // c1 = () -> new User();
User user = c1.get();

有一个参数的构造函数

有一个参数的构造函数的函数描述符是(T) -> R,可以使用Function接口,如下:

Function<Long, User> c2 = User::new;

User user = c2.apply(110L);

有三个参数的构造函数

有三个参数的构造函数的函数描述符是(T,U,V) -> R,没有现成的接口,需要自定义,如下:

@Data
@AllArgsConstructor
public class User {
  private String name;
  private Long userId;
  private Integer age;
}
@FunctionalInterface
public interface TriFunction<T,U,V,R> {
  R create(T t, U u, V v);
}
public static void main(String[] args) {
  TriFunction<String, Long, Integer, User> triFunction = User::new;
  User user = triFunction.create("tina", 12L, 13);
}

使用注意事项

Lambda表达式可以引用静态变量、成员变量和最终的(final) 或事实上最终的局部变量。

更多关于java8中lambda表达式相关方法请查看下面的相关链接

相关文章

  • SpringBoot 快速实现 api 接口加解密功能

    SpringBoot 快速实现 api 接口加解密功能

    在项目中,为了保证数据的安全,我们常常会对传递的数据进行加密,Spring Boot接口加密,可以对返回值、参数值通过注解的方式自动加解密,这篇文章主要介绍了SpringBoot 快速实现 api 接口加解密功能,感兴趣的朋友一起看看吧
    2023-10-10
  • java实现幸运抽奖功能

    java实现幸运抽奖功能

    这篇文章主要为大家详细介绍了java实现幸运抽奖功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java定义栈结构,并实现入栈、出栈操作完整示例

    Java定义栈结构,并实现入栈、出栈操作完整示例

    这篇文章主要介绍了Java定义栈结构,并实现入栈、出栈操作,结合完整实例形式分析了java数据结构中栈的定义、以及入栈、出栈、栈是否为空判断、栈大小计算、打印栈元素等相关操作技巧,需要的朋友可以参考下
    2020-02-02
  • java实现Yaml转Json示例详解

    java实现Yaml转Json示例详解

    这篇文章主要为大家介绍了java实现Yaml转Json示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • MyBatis启动时控制台无限输出日志的原因及解决办法

    MyBatis启动时控制台无限输出日志的原因及解决办法

    这篇文章主要介绍了MyBatis启动时控制台无限输出日志的原因及解决办法的相关资料,需要的朋友可以参考下
    2016-07-07
  • SpringBoot + Disruptor实现特快高并发处理及使用Disruptor高速实现队列的过程

    SpringBoot + Disruptor实现特快高并发处理及使用Disruptor高速实现队列的过程

    Disruptor是一个开源的Java框架,它被设计用于在生产者—消费者(producer-consumer problem,简称PCP)问题上获得尽量高的吞吐量(TPS)和尽量低的延迟,这篇文章主要介绍了SpringBoot + Disruptor 实现特快高并发处理,使用Disruptor高速实现队列,需要的朋友可以参考下
    2023-11-11
  • java异常机制分析

    java异常机制分析

    这篇文章主要介绍了java异常机制,包括异常机制的捕获、抛出及常见的异常机制总结,需要的朋友可以参考下
    2014-09-09
  • Java 设计模式之责任链模式及异步责任链详解

    Java 设计模式之责任链模式及异步责任链详解

    顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式
    2021-11-11
  • spring如何快速稳定解决循环依赖问题

    spring如何快速稳定解决循环依赖问题

    这篇文章主要介绍了spring如何快速稳定解决循环依赖问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • SpringBoot跨域问题的解决方法实例

    SpringBoot跨域问题的解决方法实例

    这篇文章主要给大家介绍了关于SpringBoot跨域问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05

最新评论