Java8
Lambda表达式
Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)
为什么需要Lambda表达式
在Java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法。在JavaScript中,函数参数是一个函数,返回值是另一个函数的情况是非常常见的,JavaScript是一门典型的函数式语言。比如:
var lambda = function(x) { return x + 2 };
var result = lambda(function(x) { return x * x} (3) );
alert(result);
输出:
11
Lambda表达式优势:
- 外部迭代 vs. 内部迭代
- 传递行为,而不仅仅是传递值
- 延迟加载
Java Lambda 语法结构
(param) -> { body }
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}
特殊情况
- 如果只有一个参数,可以省略小括号
param1 -> {
statment1;
statment2;
//.............
return statmentM;
}
- 如果lambda表达式body只包含一条语句时,可以省略大括号、return和语句结尾的分号,也就是可以用表达式
param1 -> { statement; }
可以
param1 -> expression
Lambda第一个例子
这个例子看起来没什么特别,跟java8之前写法没看出区别,确实没区别,但我们的关注点在于forEach方法的参数Consumer,forEach方法(java8 Iterable添加的方法)接收一个Consumer类型的参数,Consumer接口上加了FunctionalInterface注解,Consumer接口只有一个抽象方法accept(接收一个参数不返回值),这种接口称为函数式接口。
public class LambdaTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "java8");
list.forEach(new Consumer<String>() {
@Override
public void accept(String value) {
System.out.println(value);
}
});
}
}
输出:
hello
java8
函数式接口 FunctionalInterface
Java Lambda与函数式接口息息相关,学习Java Lambda需要先了解函数式接口
Conceptually, a functional interface has exactly one abstract method.
However, the compiler will treat any interface meeting the regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.
- 一个接口中,有且仅有一个抽象方法
- 如果一个接口符合函数式接口定义,不管它是否声明FunctionalInterface注解,编译器都会把它当作函数式接口
- 如果一个接口声明了FunctionalInterface注解,那么编译器会按照函数接口的定义来要求该接口
创建函数式接口实例
Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references
函数式接口实例可以通过Lambda表达式,方法引用构造方法引用等创建,Comsumer是一个函数式接口,所以第一个例子可以通过Lambda表达式来创建。
public class LambdaTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "java8");
list.forEach(value -> System.out.println(value));
}
}
输出:
hello
java8
value -> System.out.println(value)的完整写法如下:
(String value) -> { System.out.println(value);}
表示有一个输入参数,没有返回值,这与Consumer接口唯一的抽象方法accept方法签名是一致的,所以可以用value -> System.out.println(value) 表示Consumer。
默认方法
Consumer 接口还有一个方法andThen,并且有方法的实现,在java8之前,接口不可能有方法的实现,但是在java8之后,接口可以有方法的实现,但必须声明为default方法。java8为Iterable接口添加了方法forEach,如果Iterable不实现该方法,那么试想一下,用户老的代码实现了Iterable,然后用户升级到JDK1.8,肯定会报错,报接口有未实现的方法错误,为了兼容,所以java8提出了默认方法的概念。
Consumer的andThen方法,表示将两个Consumer进行组合,然后按照顺序执行两个Consumer的accept方法
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
andThen例子:
先输出字符串的小写形式,然后输出大写
public class LambdaTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("Hello", "Java8");
Consumer<String> consumer = value -> System.out.println(value.toLowerCase());
Consumer<String> consumer2 = consumer.andThen(value -> System.out.println(value.toUpperCase()));
list.forEach(consumer2);
}
}
输出:
hello
HELLO
java8
JAVA8
Lambda示例说明:
示例 | 说明 |
(int a, int b) -> {return a + b;} | 表示接收一个参数,返回一个值 |
() -> System.out.println(“hello java8”) | 表示不接收参数,不返回值 |
(String str) -> {System.out.println(str);} | 表示接收一个参数,不返回值 |
() -> 42; | 表示不接收参数,返回一个值 |
() -> {return 3.1415926;} | 表示不接收参数,返回一个值 |
例子
1、下面三个的输出是一样的:
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "java8");
// 1. 标准写法
list.forEach((String value) -> { System.out.println(value);});
// 2.特殊情况,如果参数只有一个,可以省略小括号
list.forEach(value -> { System.out.println(value);});
// 3.如果方法体只有一个语句,可以省略大括号
list.forEach(value -> System.out.println(value) );
}
输出:
hello
java8
hello
java8
hello
java8
2、 将集合中的元素全部转换成大写
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "java8");
list.forEach(value -> System.out.println(value.toUpperCase()));
}
输出:
HELLO
JAVA8
3、Stream的例子
java8最重要的两块就是Lambda表达式和Stream,这里只是介绍几个简单的例子,后续会深入分析Lambda表达式和Stream
将集合中的所有字符串转换成大写
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "java8", "welcome", "to", "java8", "world");
list.stream().map(value-> value.toUpperCase()).forEach(value -> System.out.println(value));
输出:
HELLO
JAVA8
WELCOME
TO
JAVA8
WORLD
查找集合中字符串长度大于5的元素
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "java8", "welcome", "to", "java8", "world");
list.stream().filter(value -> value.length() > 5).forEach(value -> System.out.println(value));
}
输出:
welcome