lambda用法
1、函数式接口
- 函数式接口用@FunctionalInterface注解标注的接口类,lambda必须和函数式接口的抽象函数描述一样的参数类型。
- 一个接口类只包含一个抽象方法,这个接口为函数式接口。(jdk8之后可以再接口类中声明其他方法,需要在方法前面添加default,即默认方法。)
- 关于函数式接口第一个条件:
-
- 如果一个接口只有一个抽象方法,那么这个接口是一个函数式接口;
-
- 如果我们在某个接口上声明了FunctionalInterface接口,如果不满足函数式 接口的要求,则会报错;
-
- 如果某个接口只有一个抽象方法,但是我们并没有给该接口声明FunctionalInterface注解,这个时候,编译器还是会将此接口视为函数式接口。
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
- 可以使用lambda接口实现Converter接口
Converter<String, Integer> converter = (param) -> Integer.valueOf(param);
Integer result = converter.convert("101");
System.out.println(result);
new Thread(() -> System.out.println("hello lambda)).start();
2、方法引用
- 方法引用是lambda表达式的一个简化方法。语法结构为:
ObjectRef::methodName
2.1、静态方法引用
public class ReferenceTest {
public static void main(String[] args) {
Converter<String, Integer> converter = ReferenceTest::String2Int;
System.out.println(converter.convert("110"));
}
static Integer String2Int(String from) {
return Integer.valueOf(from);
}
}
2.2、实例方法引用
Helper helper = new Helper();
Converter<String, Integer> converter = helper::String2Int;
System.out.println(converter.convert("120"));
3、Stream
3.1、stream简介
- stream是一个可以对个序列中的元素执行各种计算操作的一个元素序列。下例为链式调用将中间操作串联起来。
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("a1", "a2", "b1", "b2", "c1", "c2"));
list.stream().filter(s -> s.startsWith("c")).map(String::toUpperCase).sorted().forEach(System.out::println);
}
- stream包含中间和最终两种形式的操作。
- 中间操作返回值是一个stream,最终操作只能返回void或者一个非stream的结果。如filter,map,sorted是中间操作,forEach是最终操作。
- 方法接口的行为基本上都是无干扰和无状态。无干扰为该方法不修改stream的底层数据源;无状态为操作的执行是独立的。
3.2、streams分类
- 可以从不同的数据源创建stream。Collections、Lists、Sets这些类中新增stream()(顺序stream)和parallelStream()(并发stream)方法。
- List对象上调用stream()方法可以返回一个常规的对象流。
Arrays.asList("a1", "a2", "a3")
.findFirst().ifPresent(System.out::println);
- 可以直接用stream创建一个collection。使用Stream.of()方法就能从一组对象创建一个stream对象。
Stream.of("a1", "a2", "a3")
.findFirst().ifPresent(System.out::println);
- IntStream、LongStream、DoubleStream可以处理基本类型:int、long、double。可以用range()方法替换掉for循环。
IntStream.range(1, 4).forEach(System.out::println);
Arrays.stream(new int[] {1,2,3})
.map(n -> 2 * n + 1)
.average()
.ifPresent(System.out::println);
)
- 可以通过常规对象流的mapToInt()、mapToObj()等方法完成常规流与基本类型流的互相转换。
IntStream.range(1, 4).mapToObj(i -> "a" + i).forEach(System.out::println);
3.3、处理顺序
- Laziness(延迟加载)是中间操作的一个重要特性。
4、为何需要使用lambda表达式
- 在java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法;
- 在JavaScript中,函数参数是一个函数,返回值是另一个函数的情况是非常常见的。JavaScript是一种非常典型的函数式语言。
- 同为面向对象语言。
5、lambda表达式结构
5.1、lambda表达式基本结构
// 基本结构(一般结构)
(param1, param2, param3) -> {
}
// list使用
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
list.forEach(integer -> sout(integer));
list.forEach(System.out::println); // 方法引用 methodReference
6、lambda表达式作用
- lambda表达式为java添加了确实的函数式编程特性;
- 在将函数作为一等公民的语言当中,lambda表达式的类型是函数。**但在java中,lambda表达式是对象,**他们必须依附于一类特别的对象类型-函数式接口(functionalInterface)。