zoukankan      html  css  js  c++  java
  • java 8 总结 之lambda

    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
    

    主要有三类:

    • 指向静态方法的方法引用,如:Integer::parseInt
    • 指向任意类型实例方法的方法引用,如:String::length
    • 指向现有对象的实例方法的方法引用,如: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) 或事实上最终的局部变量。
  • 相关阅读:
    用jmeter进行多用户并发压力测试
    Jmeter使用流程及简单分析监控
    检查点--JMeter也有之二“检查点”
    浅谈如何做好Bug回归验证?
    手机APP测试技术-整体测试流程框架
    常用的sql语句
    Jmeter实时性能测试数据的监控
    Jmeter插件之PerfMon监控插件使用说明
    Requests: 让 HTTP 服务人类
    安装mysql数据库图文教程
  • 原文地址:https://www.cnblogs.com/shoren/p/java8-lambda.html
Copyright © 2011-2022 走看看