【Java】拉姆da表明式和匿名内部类(I)

Java,本文git地址.md)

前言

Java
Lambda表达式的3个重中之重用法是简化某个匿名内部类Anonymous Classes)的写法。实际上Lambda表明式并不只是匿名内部类的语法糖,JVM内部是因此invokedynamic一声令下来达成Lambda表达式的。具体原理放到下一篇。本篇我们首先感受一下使用Lambda表达式带来的有益之处。

取代某个匿名内部类

本节将介绍怎么样行使拉姆da表明式简化匿名内部类的书写,但Lambda表明式并不能够取代全数的匿名内部类,只可以用来代替函数接口(Functional
Interface)
的简写。先别在乎细节,看多少个例证再说。

事例1:无参函数的简写

倘若须求新建叁个线程,一种普遍的写法是那般:

// JDK7 匿名内部类写法
new Thread(new Runnable(){// 接口名
    @Override
    public void run(){// 方法名
        System.out.println("Thread run()");
    }
}).start();

上述代码给Tread类传递了一个匿名的Runnable对象,重载Runnable接口的run()艺术来贯彻相应逻辑。那是JDK7以及从前的大规模写法。匿名内部类省去了为类起名字的烦扰,但依旧不够简化,在Java
第88中学得以简化为如下方式:

// JDK8 Lambda表达式写法
new Thread(
        () -> System.out.println("Thread run()")// 省略接口名和方法名
).start();

上述代码跟匿名内部类的意义是同样的,但比匿名内部类更进一步。那里连接口名和函数名都一同省掉了,写起来越发神清气爽。借使函数体有多行,能够用大括号括起来,就像是这么:

// JDK8 Lambda表达式代码块写法
new Thread(
        () -> {
            System.out.print("Hello");
            System.out.println(" Hoolee");
        }
).start();

事例2:带参函数的简写

只要要给一个字符串列表通过自定义相比较器,依照字符串长度举行排序,Java
7的书写情势如下:

// JDK7 匿名内部类写法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, new Comparator<String>(){// 接口名
    @Override
    public int compare(String s1, String s2){// 方法名
        if(s1 == null)
            return -1;
        if(s2 == null)
            return 1;
        return s1.length()-s2.length();
    }
});

上述代码通过中间类重载了Comparator接口的compare()主意,达成相比逻辑。选拔拉姆da表达式可简写如下:

// JDK8 Lambda表达式写法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, (s1, s2) ->{// 省略参数表的类型
    if(s1 == null)
        return -1;
    if(s2 == null)
        return 1;
    return s1.length()-s2.length();
});

上述代码跟匿名内部类的效应是平等的。除了省略了接口名和章程名,代码中把参数表的类型也简单了。那得益于javac体系预计机制,编写翻译器能够依据上下文消息推断出参数的品类,当然也有揣摸战败的时候,那时就供给手动指明参数类型了。注意,Java是强类型语言,每种变量和目的都必不可少有备受关注的项目。

简写的基于

莫不你曾经想到了,可见选拔拉姆da的依据是必须有照应的函数接口(函数接口,是指当中唯有1个空洞方法的接口)。那或多或少跟Java是强类型语言吻合,约等于说你并不可能在代码的别的市方任性的写Lambda表达式。实际上Lambda的项目便是对应函数接口的品种Lambda表明式另1个基于是项目推测机制,在上下文音讯丰裕的图景下,编写翻译器可以测算出参数表的门类,而不须求显式指名。Lambda表明越多合法的书写格局如下:

// Lambda表达式的书写形式
Runnable run = () -> System.out.println("Hello World");// 1
ActionListener listener = event -> System.out.println("button clicked");// 2
Runnable multiLine = () -> {// 3 代码块
    System.out.print("Hello");
    System.out.println(" Hoolee");
};
BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4
BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5 类型推断

上述代码中,1显得了无参函数的简写;2处展现了有参函数的简写,以及项目推测机制;3是代码块的写法;4和5重复彰显了体系估摸机制。

自定义函数接口

自定义函数接口很不难,只须求编写制定叁个唯有二个架空方法的接口即可。

// 自定义函数接口
@FunctionalInterface
public interface ConsumerInterface<T>{
    void accept(T t);
}

上边代码中的@FunctionalInterface是可选的,但丰盛该标注编写翻译器会帮你检查接口是不是适合函数接口规范。就像参与@Override标注会检查是或不是重载了函数一样

有了上述接口定义,就足以写出近似如下的代码:

ConsumerInterface<String> consumer = str -> System.out.println(str);

更进一步的,还是能够这么使用:

class MyStream<T>{
    private List<T> list;
    ...
    public void myForEach(ConsumerInterface<T> consumer){// 1
        for(T t : list){
            consumer.accept(t);
        }
    }
}
MyStream<String> stream = new MyStream<String>();
stream.myForEach(str -> System.out.println(str));// 使用自定义函数接口书写Lambda表达式

参考文献

  1. The Java® Language
    Specification
  2. http://viralpatel.net/blogs/lambda-expressions-java-tutorial/
  3. 《Java 8函数式编制程序
    [英]沃伯顿》

相关文章