java8中lambda表达式的用法总结
创始人
2024-12-25 04:41:48
0次

java8之lambda表达式

目的:行为参数化

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

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

举例:

() -> 42  //参数为空,返回一个int(List 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返回一个函数式接口,() -> Stringpublic Callable fetch() {   return () -> "Tricky example ;-)";}

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

Predicate

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

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

使用

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

Consumer

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

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

Function

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

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

特定方法避免装箱操作

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

总结

(T) ->bool      java.util.function.Predicate              (T) -> void      java.util.function.Consumer              (T) -> R      java.util.function.Function              (T,U) -> R      java.util.function.BiFunction              () -> T      java.util.function.Supplier

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

特殊的void兼容规则:

// Predicate返回了一个boolean Predicate p = s -> list.add(s); // Consumer返回了一个void Consumer 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  指向任意类型实例方法的方法引用,如:String::length  指向现有对象的实例方法的方法引用,如:User::getUserId

构造函数引用

无参构造函数

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

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

有一个参数的构造函数

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

Function c2 = User::new;User user = c2.apply(110L);

有三个参数的构造函数

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

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

使用注意事项

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

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...