zoukankan      html  css  js  c++  java
  • 再来看看Java8的新特征——lambda表达式

    什么是lambda表达式?

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

    比如说new一个Thread的传统写法如下

    Thread t = new Thread(new Runnable() {
     public void run(){
     System.out.println("Hello world");
     }
    }); 
    

    那么利用lambda表达式的写法就是

    Thread t = new Thread(() -> System.out.println("Hello world")); 
    

    ->左边的就是参数列表,->右边的就是函数主体

    函数式接口

    为什么@FunctionalInterface注解修饰的类只能有一个抽象函数

    查看Java8的源码,被@FunctionalInterface修饰的函数叫做函数式接口,例如Predicate,这些类往往只有一个抽象函数,那是因为“Lambda表达式理解为简洁地表示可传递的匿名函数”,直接使用的匿名函数的时候没有指定函数名称,所以,如果有两个及以上抽象函数的时候,虚拟机就不知道你要执行哪个方法了,如上例中Runnable的run()方法,我们参数列表部分只使用了(),并没有声明调用的函数名。

    JDK自带的函数式接口都在java.util.function路径下,常用的有

    public interface Predicate<T>{
     boolean test (T t);
    } 
    public interface Consumer<T> {
     void accept(T t);
    }
    public interface Function<T, R> {
     R apply(T t);
    }
    ...
    

    函数式接口使用示例

    //源码部分
    @FunctionalInterface
    public interface Predicate<T>{
     boolean test(T t);
    }
    //方法构建
    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
     List<T> results = new ArrayList<>();
     for(T s: list){
     if(p.test(s)){
     results.add(s);
     }
     }
     return results;
    }
    //使用示例,通过filter方法,筛选出String不为空的数据
    Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
    List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate); 
    

    其他函数式接口使用示例

    为什么lambda表达式使用局部变量必须是final的?

    lambda表达式主体部分除了使用参数列表的数据,还可以使用lambda表达式外部的局部变量,但是这些局部变量只能声明一次,否则就会报错。

    int portNumber = 1337;
    //此时会报错,portNumber必须被final修饰
    Runnable r = () -> System.out.println(portNumber);
    portNumber = 31337; 
    

    因为lambda表达式主体可看作是匿名内部类,访问外部局部变量是需要final的。从线程的角度来说,就是局部变量是一个线程(假设叫线程A),lambda表达式主体是另外一个线程(线程B),当线程A结束的时候,线程B还要访问线程A的数据,肯定是不行的,所以线程B中的变量实质上不是指向线程A中的变量,而是拷贝了一份出来,所以必须保证拷贝出来的数据是不可以改变的。

    方法引用

    lambda表达式还有一个非常方便的地方,就是方法引用,可以通过类名::方法名的形式直接使用方法。

    例如

    //静态方法
    Integer::parseInt
    //对象的普通方法
    String::length
    //构造方法
    Apple::new
    

    复合lambda表达式的用法

    lambda表达式还可以链式调用,同时拥有与或非(negate、and和or)的逻辑判断

    //链式调用
    inventory.sort(comparing(Apple::getWeight)
     .reversed()
     .thenComparing(Apple::getCountry));
     
    //非
    Predicate<Apple> notRedApple = redApple.negate();
    //与
    Predicate<Apple> redAndHeavyApple =
     redApple.and(a -> a.getWeight() > 150);
    //或
    Predicate<Apple> redAndHeavyAppleOrGreen =
     redApple.and(a -> a.getWeight() > 150)
     .or(a -> "green".equals(a.getColor())); 
    

    函数复合

    Function函数接口提供了两个方法对数据做连续操作,andThen和compose方法。

    Function<Integer, Integer> f = x -> x + 1;
    Function<Integer, Integer> g = x -> x * 2;
    Function<Integer, Integer> h = f.compose(g);
    int result = h.apply(1);
    //输出3 ==> )(1*2)+1
    

    andThen方法相当于先执行f函数,再执行g函数。

    Function<Integer, Integer> f = x -> x + 1;
    Function<Integer, Integer> g = x -> x * 2;
    Function<Integer, Integer> h = f.andThen(g);
    int result = h.apply(1); 
    //输出4 ==> (1+1)*2
    

    compose方法相当于先执行g函数,再执行f函数。

    接下来

    接下来会梳理流的相关知识点、和其他(注入Optionnal、新的时间工具、默认方法等知识)。

  • 相关阅读:
    骑行的乐趣
    亲子运动会
    【转载】程序员接私活经验总结,来自csdn论坛语录
    【原创】Asp.Net MVC 学习笔记之使用Model验证
    【转载】经典js技巧
    【原创】关于Sqlserver的LogFiles超大的问题
    【总结】Winform编程常用小技巧
    【总结】WebBrowser相关资料索引
    【原创】Asp.Net MVC学习笔记之使用AcceptVerbs标签来制定Action的响应行为
    【转载】一个资深SOHO程序员对新人的建议网上接活(转自CSDN)
  • 原文地址:https://www.cnblogs.com/pjjlt/p/11831576.html
Copyright © 2011-2022 走看看