学习笔记
作为学习笔记我就不写历史啥的了,完全随心记。
首先,Java lamda的标准写法
(param1, param2) -> {expression};
param为匿名内部类中的函数参数,expression为函数里面的所有语句,常写的例子
new Thread(new Runnable() {
@Override
public void run() {
// doSomething
System.out.println("test");
}
}).start();
这里匿名内部类可省略,编译器会自动推断,函数没有参数就可直接使用括号,函数内部语句直接写到花括号中,lambda表达式如下
new Thread(() -> {
System.out.print("test");
}).start();
接下来又是很重要的一点
如果参数只有一个,小括号可以去掉 即为
param -> {expression};
比如
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
e.getActionCommand();
}
});
这里只有ActionEvent类的一个对象e为参数,里面有两行代码,所以可以省略掉参数外面的括号,而且参数可以自己定义为任何合法的标识符,但是在函数内部引用的时候需要与你定义的参数保持一致,这里就变成了
jButton.addActionListener(w-> {
System.out.println("Action performed");
w.getActionCommand();
});
好的,语法还可以进一步简化
如果表达式只有一行,大括号,可以去掉,并且这一行最后的分号结尾,要去掉
最开始写的新建线程的lambda表达式可以进一步简化成这样
new Thread(() -> System.out.println("test")).start();
那么,这是java8的新特性,什么情况下能使用lambda表达式呢?我们看到的形式都是在创建匿名内部类的时候使用lambda表达式,创建形式就是new一个某个接口类型的对象,然后在内部类中实现接口的方法。那么,这些接口都有什么特点呢,通过Idea打开Runnable接口的定义,会发现接口上面有这么一个注解
@FunctionalInterface
即函数式接口,那我们再看看这个接口的定义吧
An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification.
Conceptually, a functional interface has exactly one abstract method. Since {@linkplain java.lang.reflect.Method#isDefault() default methods} have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of {@code java.lang.Object}, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from {@code java.lang.Object} or elsewhereNote that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.
If a type is annotated with this annotation type, compilers are required to generate an error message unless:
- The type is an interface type and not an annotation type, >enum, or class.
- The annotated type satisfies the requirements of a functional interface.
However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a {@code FunctionalInterface} annotation is present on the interface declaration.
从这段解释里面我们可以提取到几个要点
- 首先这个注解是定义在接口上面的
- 第二,接口由这个注解定义的接口应该有且仅有一个抽象方法,但是由于Java8引入了接口的default方法,default方法有实现,所以不算抽象方法,如果接口覆写了object的一个public方法,也不计算在这个抽象方法的名额里面,因为所有的接口的实现都会实现object的方法。
- 第三,函数式接口的实例可以lambda expressions, method references, or constructor references的形式出现
- 第四,不在以上范围内的接口如果使用了FunctionalInterface注解,编译器会报错
- 最后,虽然有些接口没有加上FunctionalInterface注解,但是编译器会把满足函数式接口的定义的接口看作FunctionalInterface,也就是说这些接口的实例也可以用lambda表达式的形式来写。
也就是说,所有满足函数式接口的接口的实例都可以变为lambda表达式,不满足的则会在创建的时候报错。
以下定义的接口就满足函数式接口的定义
public interface MyTest {
String[] test(String str);
default void test2() {
System.out.println("test");
}
String toString();
}
虽然没有加上FunctionalInterface注解,但是在使用的时候还是可以使用Lambda表达式
public class MyTestMain {
public static void main(String[] args) {
// MyTest.test(str)常规写法;
String[] test = test(new MyTest() {
@Override
public String[] test(String str) {
return str.split("");
}
});
//变为lambda表达式
test(s->s.split(""));
for (String s : test) {
System.out.println(s);
}
}
public static String[] test(MyTest test) {
return test.test("strd");
}
}
到这里就可以使用lambda表达式写很多有意思的代码啦,仔细观察,java集合里面好多的匿名内部类都可以使用lambda表达式来简写,我们看了函数式接口用lambda表达式来表示的,当然要介绍一下使用方法引用的形式咯
如果,lambda 表达式只有一个参数,表达式只有一个, 且表达式调用了这个的参数本身,那么这个参数可以省略,并且变成方法引用的形式
对象::方法名
对象为表达式中的对象,方法为该对象调用的方法
appleStore.forEach(apple -> System.out.println(apple));
apple为参数,表达式里面调用了apple,且表达式只要一个,可以转化为方法引用的形式
appleStore.forEach(System.out::println);
方法引用还有一种形式
当表达式为前述参数只调用一次自己的方法,也可以变为方法引用
参数类名::方法名
int redPriceSum = appleStore.stream()
.filter(apple -> apple.getColor().equals("red"))
.mapToInt(apple1->apple1.getPrice).sum();
可以看到mapToInt方法中的lambda表达式符合上述方法引用的形式,所以可以简化为
Apple::getPrice
其中Apple为apple对象的类名
大致就是这些,想要了解更多使用的实例的可以去翻一翻集合的源码,比如集合类的foreach方法,参数就是一个函数式接口,可以转换为lambda表达式,真的太宝藏啦!我现在才发现在Idea上面看源码是多么有意思,以后要常看常学!