Lambda, Stream and Function-style programmingsome notes of L
Lambda表达式
Lambda表达式可以被理解为可以传递的匿名函数的简洁表示:它没有名称,但它有一个参数列表、一个主体、一个返回类型,可能还有一个可以抛出的异常列表。
- 匿名的,没有像普通的方法那样有显示的名称;
- 没有关联的具体类,但是有参数列表、方法体、返回值甚至可以抛出异常;
- 可以像变量一样传递到一个方法中,或者存储在变量中
- 简洁的,不必像匿名类一样写很多样板代码;
可以在函数式接口的上下文中使用lambda表达式。函数式接口是只有一个抽象方法的接口。只要它只指定了一个抽象方法,如果接口有许多默认方法,它仍然是一个函数式接口。
@FunctionalInterface
public interface Runnable {
/**
* Runs this operation.
*/
void run();
}
函数描述符
函数接口抽象方法的签名基本上描述了lambda表达式的签名。我们称这个抽象方法为函数描述符。
关于 @FunctionalInterface 此注释用于表示该接口旨在成为函数式接口。如果使用@FunctionalInterface注释定义接口,并且它不是功能接口,编译器将返回一个有意义的错误。例如,错误消息可能是“Multiple non-overriding abstract methods found in interface”,以表明有多个抽象方法可用。@FunctionalInterface注释不是强制性的,但当接口为此目的而设计时,使用它是一个很好的做法。
类型检查、类型推断和限制
Lambda的类型是从使用lambda的上下文中推断出来的。上下文中lambda表达式的预期类型(例如,传递给的方法参数或分配给的方法变量)称为目标类型。
Lambda使用局部变量
Lambda可以不受限制地捕获(即在其主体中引用)实例变量和静态变量。但局部变量必须明确为final或者实际是final(只赋值一次)。局部变量的作用域仅限于当前方法或块,这意味着它们不会被多个线程同时访问。如果允许lambda表达式修改局部变量,可能会导致线程安全问题。通过限制lambda表达式只能访问final或有效最终变量,Java确保了这些变量在lambda表达式中是不可变的。这有助于避免并发访问时的数据竞争和不一致问题。
方法引用
方法引用可以被视为只调用特定方法的lambdas的简写。
Stream
定义:stream是来自支持数据处理操作的源的元素序列。stream通过声明式的风格处理数据,我们可以通过Stream提供的API实现一系列数据操作而不是重复实现这些方法。
Stream vs Collection
collection中的元素是计算完成以后放入其中的,相比之下,流是一个概念上固定的数据结构(不能从中添加或删除元素),其元素是按需计算的。 Stream中的数据只能被消费一次,与iterator类似:
collection使用显示迭代的方式遍历集合,但是Stream使用隐式的方式,这意味着遍历的顺序是不确定的,被优化过的,比如可以使用并行化处理。
Operations
intermediate operation
如过滤或排序,返回另一个stream作为返回类型,这允许操作连接以形成查询。重要的是,在流管道上调用终端操作之前,中间操作不会执行任何处理——它们是懒惰的。这是因为中间操作通常可以通过终端操作合并并处理为单通道。
terminal operations
产生非stream结果,比如List,Integer。
Working with streams
综上所述,处理流通常涉及三个项目: Java 8 in Action: Lambdas, Streams, and functional-style programming
- A data source (such as a collection) to perform a query on
- A chain of intermediate operations that form a stream pipeline
- A terminal operation that executes the stream pipeline and produces a result
Filtering and slicing
Stream<T> filter(Predicate<? super T> predicate);
Filtering unique elements
返回stream,过滤掉其中的重复元素。
截断Stream
通过java.util.stream.Stream#limit方法,截断Stream。
Skipping elements
丢弃前n个元素并返回stream。
map
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
将mapper方法应用在每个stream的元素上,返回一个新类型的Stream。
FlatMap
它用于将一个流中的每个元素转换为另一个流,然后将这些流扁平化为一个单一的流。flatMap 在处理嵌套的集合或需要将多个流合并为一个流时特别有用。
anyMatch, allMatch and noneMatch
Returns whether any elements of this stream match the provided predicate.
boolean anyMatch(Predicate<? super T> predicate);
Returns whether all elements of this stream match the provided predicate
boolean allMatch(Predicate<? super T> predicate);
Returns whether no elements of this stream match the provided predicate
boolean noneMatch(Predicate<? super T> predicate);
reduce
T reduce(T identity, BinaryOperator<T> accumulator);
Numeric streams
IntStream, DoubleStream, LongStream,操作更加简单,但是装箱操作具有一定性能开销。
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
使用boxed转换为包装类的Stream。
构建Stream
- java.util.stream.Stream#of(T) or java.util.stream.Stream#empty
- 从array构建,java.util.Arrays#stream(int[])
Collecting data with streams
Collector接口方法的实现定义了如何在流上执行reduce操作。
计算stream元素个数
java.util.stream.Collectors#counting
最大值与最小值
java.util.stream.Collectors#maxBy,
java.util.stream.Collectors#minBy
同时获取最大值、最小值、平均值、sum及count
joining
调用每个Stream每个元素的toString方法,连接成单一字符串。
grouping
将stream中的元素进行分类, java.util.stream.Collectors#groupingBy(java.util.function.Function<? super T,? extends K>) Function类型的参数classifier产生的值作为key,其value是一个list,我们也可以不使用list,使用其他类型的Collector。
partioning
划分,是一种特殊的group操作。
转载自:https://juejin.cn/post/7422154695743406092