zoukankan      html  css  js  c++  java
  • Lambda 表达式

    lambda
    什么是 Lambda 表达式,我觉得是我们开始学习 Lambda 表达式之前应该要弄清楚的一个概念。我们可以把 Lambda 表达式理解为简洁地表示可以传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。[1]
    简单的说 Lambda 有以下的特点:
    1.匿名,它没有一个明确的名字。
    2.函数,是的, Lambda 表达式确实是一种函数,这毋庸置疑。
    3.传递,Lambda 表达式可以作为参数传递给方法。
    4.简洁,没有什么比 Lambda 更加简洁的语法了(Java 中)

    Lambda 管中窥豹

    概念说完我们就开始我们的代码之旅——Lambda 的语法:
    (paramenters) -> expression
    或者
    (paramenters) -> { statements; }

    Lambda 参数 + 箭头 + Lambda 主体 构成。在 Java8 中 Lambda 表达式的体现形式有以下 5 中:
    1.(String s) -> s.length()
    这个 Lambda 表达式具有一个 String 类型的参数并且返回一个 Int。[2]

    2.(Apple a) -> a.getWeight() > 150
    这个 Lambda 表达式具有一个 Apple 类型的参数并且返回一个 Boolean。

    3.(int x, int y) -> (System.out.println(x + y))
    这个 Lambda 表达式具有一个 String 类型的参数然而它并没有返回值(void 返回)。

    4.() -> 93
    这个 Lambda 表达式没有参数,返回一个 Int。

    5.(Apple a, Apple b) -> a1.getWeight().compareTo(a2.getWeight())
    最后一个 Lambda 表达式具有两个 Apple 类型的参数,返回一个 Int。

    在哪里以及如何使用 Lambda?

    我们刚刚已经了解了 Lambda 表达式的语法以及基本的 5 中表现形式,那么应该在哪里使用 Lambda 表达式以及如何使用 Lambda 表达式呢?一般我们可以在函数式接口[3]上使用 Lambda 表达式。附录 A 列举了 JDK 8之前已有的函数式接口。

    我们最常用的应该是 java.lang.Runnable 接口了,在 Java8 之前要开启一个多线程,那么必定会写以下这段代码:

    Runnable run = new Runnable(){
        public void run(){
            System.out.println("Start a  new Thread");
        }
    };
    

    按照正常的缩进,我们开启一个线程最少需要写 5 行代码,其中只有一行使我们的主要核心,其他 4 行代码都是为之服务的,或者称之为样板式代码。有点像 JDBC 数据库连接池一样,先要创建连接对象...最后关闭连接池。而使用 Lambda 表达式可以有效的缩短代码的行数,并且让代码写的更加的清晰。

    Runnable run = () -> System.out.println("Start a  new Thread");
    

    没错,就这么简单,一切显得是那么的优雅和华丽,没有什么多余的样板式代码,一眼就能够看代码的意图。再也不用主动过滤掉无用的代码了,应为留下来的都是有用的代码。可能你一时还不习惯这样的方式或是写法,没关系接着往下,会有更多的列子和惊喜。

    刚刚我们用函数式接口来使用 Lambda 表达式,还有一种方式是使用函数描述符——函数式接口的抽象方法基本上就是 Lambda 表达式的签名。就拿刚刚线程的代码来说,Runnable 接口可以看做一个什么都没有返回的的函数签名,应为它只有一个 run 的抽象方法,这个方法既不接受参数也不返回参数。

    public void process(Runnable r){
        r.run();
    }
    
    process(() -> System.out.println("Start a  new Thread"));
    

    来一个栗子

    废话不多说,先上代码:

    public class ExecuteAround {
    
    	public static void main(String ...args) throws IOException{
    
            // method we want to refactor to make more flexible
            String result = processFileLimited();
            System.out.println(result);
    
            System.out.println("---");
            
            // 使用 Lambda 表达式改进
            String oneLine = processFile((BufferedReader b) -> b.readLine());
            System.out.println(oneLine);
    
            String twoLines = processFile((BufferedReader b) -> b.readLine() + b.readLine());
            System.out.println(twoLines);
    
    	}
    
        public static String processFileLimited() throws IOException {
            try (BufferedReader br =
                         new BufferedReader(new FileReader("data.txt"))) {
                return br.readLine();
            }
        }
    
    
    	public static String processFile(BufferedReaderProcessor p) throws IOException {
    		try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){
    			return p.process(br);
    		}
    
    	}
    
    	public interface BufferedReaderProcessor{
    		public String process(BufferedReader b) throws IOException;
    
    	}
    }
    

    这个例子就是我们平时处理资源的一段代码,我们打开一个资源,做一些处理(读啊,写啊),然后关闭资源。这里对比了使用传统方式和使用 Lambda 表达式的方式来写这一段代码。这里可以看出使用 Lambda 表达式可以使代码更加灵活,在这段代码中的提现是:可以由传入参数的不同而决定方法的实现。

    使用函数式接口

    正如前面说的,函数式接口定义且只定义了一个抽象方法。我们在 JDK8 之前常用的如 Comparable、Runnable 和 Callable 等,在 Java8 中伟大的设计师又引进了几个新的函数式接口,这里介绍其中的一些作为了解。

    Predicate

    java.util.function.Predicate 接口定义了一个名叫 test 的抽象方法,它接受泛型 T 对象,并返回一个 boolean。

    @FunctionalInterface
    public interface Predicate<T>{
        boolean test(T t);
    }
    
    public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
    		List<Apple> result = new ArrayList<>();
    		for(Apple apple : inventory){
    			if(p.test(apple)){
    				result.add(apple);
    			}
    		}
    		return result;
    }   
    
    List<Apple> greenApples = filter(inventory, (Apple a) -> "green".equals(a.getColor()));
    System.out.println(greenApples);
    

    Consumer

    java.util.function.Consumer 接口定义了一个名叫 accept 的抽象方法,它接受泛型 T 对象,但并没有返回值。如果需要访问类型 T 的对象,并对其执行某些操作,就可以使用这个接口。比如循环一个对象。

    @FunctionalInterface
    public interface Consumer<T>{
        void accept(T t);
    }
    
    public static <T> forEach(List<T> list, Consumer<T> c){
        for(T i: list){
            c.accept(i);
        }
    }
    
    List<int> list = Arrays.asList(1, 2, 3, 4, 5);
    //Lambda 是 Consumer 中 accept 方法的实现
    forEach(list, (Integer i) -> System.out.println(i))
    

    Function

    java.util.function.Function<T, R> 接口定义了一个叫做 apply 的方法,该方法接受一个泛型的 T 对象,返回一个泛型的 R 对象。如果你需要一个 Lambda 表达式将对象的信息映射到输出,那么久可以使用这个接口。

    @FunctionalInterface
    public interface Function<T, R>{
        R apply(T t);
    }
    
    public static <T, R> List<R> map(List<T> list, Function<T, R> f){
        List<R> result = new ArrayList<>();
        for(T s: list){
            result.add(f.apply(s));
        }
        return result;
    }
    
    List<int> list = Arrays.asList("java8", "in", "action");
    List<Interger> listFun = map {
        list,(String s) -> s.length();
    };
    

    附录A

    JDK 8之前已有的函数式接口:
    java.lang.Runnable
    java.util.concurrent.Callable
    java.security.PrivilegedAction
    java.util.Comparator
    java.io.FileFilter
    java.nio.file.PathMatcher
    java.lang.reflect.InvocationHandler
    java.beans.PropertyChangeListener
    java.awt.event.ActionListener
    javax.swing.event.ChangeListener

    本文由个人 hexo 博客 co2fe.com 迁移
    date: 2017-07-16 22:03:37


    1. Java8 实战中对 Lambda 的描述。 ↩︎

    2. 注意 Lambda 没有 return 语句,其本身隐含了一个 return,故不用显示声明出来。 ↩︎

    3. 函数式接口(Functional Interface)是Java 8对一类特殊类型的接口的称呼。 这类接口只定义了唯一的抽象方法的接口。 ↩︎

  • 相关阅读:
    计算机算法设计与分析之棋盘覆盖问题
    在uboot里面加入环境变量使用run来运行
    软件project师的属性与发展
    Oracle 表三种连接方式(sql优化)
    POJ 1700 cross river (数学模拟)
    八:Java之I/O
    为 Python Server Pages 和 Oracle 构建快速 Web 开发环境。
    WebBot
    WebBrowserProgramming
    Skulpt
  • 原文地址:https://www.cnblogs.com/manastudent/p/10190849.html
Copyright © 2011-2022 走看看