lambda表达式
lambda表达式出现最显著的优点就是它简化(注意不是取代)了匿名内部类。底层lambda表达式和匿名内部类并不相同,但是这里并不打算深入,而是打算简简单单只是从吃糖者的角度来看。
基础用法就是如果一个接口里面只有一个abstract函数,就可以开心使用lambda了。官方一点的说法是函数接口可以使用lambda表达式。函数接口,是指内部只有一个抽象方法的接口。
JDK8内置了一些核心的函数式接口。
1 | package java.util.function; |
也可以自己定义一个接口,里面只有一个函数,并且推荐加上@FunctionalInterface
这个注解,作用与@Override
类似,让编译器帮忙检查。
所以用起来就会比较规范:
1 | public class Main { |
方法引用
另外一种lambda的表现形式,有三种使用方法:
- 对象::实例方法,
list::add
- 类::方法(静态和非静态都可以),
String.out::println
- 类::构造方法,
String::new
比如我们经常要打印某些信息,但是显然System.out这个类里面的println方法已经替我们实现了,所以我们其实可以直接用System.out::println
来代替它(当然在这个例子中可能并没那么简便…),而且调用的方法需要和接口中的方法调用和返回值都相同。
Stream API
首先它是一个流,所以是用来进行数据操作的。其次它和普通IO流的区别就是,它面向的是集合和数组等;它对这些数据源进行一系列的操作,比如切片等,然后产生新的流,原来的数据源不发生任何变化。
- 创建源
- Collection接口里提供了stream()和parallelStream(),所以集合都可以直接使用。
- 通过
Arrays.stream()
静态方法来创建数组的静态流。 - 通过
Stream.of()
方法来创建。 - 创建无限流
- 迭代的方式:
Stream.iterate(seed,一个表达式)
- 生成的方式:
Stream.generate(Supplier t)
- 迭代的方式:
- 中间操作:内容较多,单独作为一章。中间操作并不会执行任何操作,直到终止操作才会执行——惰性求值。
- 终止操作
中间操作
filter
1 | Stream<T> filter(Predicate<? super T> predicate); |
传入了一个断言接口,所以我们可以直接在其中用lambda来使用。
例子:
1 | List<String> strings = Arrays.asList("aa", "bb", "cc"); |
limit
1 | Stream<T> limit(long maxSize); |
使用起来非常方便。它会产生短路,即只要知道对应的数量,后续的迭代操作就不需要执行了。
skip
1 | Stream<T> skip(long n); |
emmm 和limit形成互补的操作,跳过前n个元素。
distinct
1 | Stream<T> distinct(); |
通过hashCode和equals方法来进行判断的。