java函数式编程笔记

本文详细探讨了Java 8中的函数式编程概念,包括lambda表达式的使用,函数式接口Function、Consumer、Supplier和Predicate的介绍及其在实际编程中的应用。此外,文章还介绍了Stream API,讲解了其与Spark RDD的相似性,以及Stream的惰性求值、短路操作、并行化处理等特点,并阐述了Collectors在数据转换和收集中的作用。通过对java.util.stream包中相关类和接口的解析,揭示了Stream操作的内部工作原理,如Pipeline、ForkJoinTask和CountedCompleter等,展示了函数式编程如何影响并发代码设计和并发性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java函数式编程:
http://www.ruanyifeng.com/blog/2012/04/functional_programming.html
https://en.wikipedia.org/wiki/Lambda_calculus
http://www.defmacro.org/2006/06/19/fp.html
https://kb.cnblogs.com/page/154935/
https://www.cnblogs.com/snowInPluto/p/5981400.html
https://my.oschina.net/thinwonton/blog/2992751
https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/
https://www.cnblogs.com/figure9/p/java-8-lambdas-insideout-language-features.html
http://www.importnew.com/28139.html
函数式编程和面向对象编程并列?
(面向对象编程是对数据抽象,而函数式编程是对行为抽象;)
lambda表达式可以取代匿名内部类;
(Lambda表达式中的参数类型由编译器推断得出;)
Lambda表达式引用的是值,而不是变量;
(虽然无需将变量声明为final,但该变量在既成事实上必须是final; 所以Lambda表达式也被称为闭包;)

java function:
java function即高阶函数(接收函数参数的函数),主要有4大类,分别是Function、Consumer、Supplier、Predicate;
(Function即数据转换器,Supplier即数据提供器,Consumer即数据消费器,Predicate即条件测试器;)
(注意:Operator来自Function,见BinaryOperator)
(Function的扩展有BiFunction、LongFunction、IntFunction、DoubleFunction、ToIntFunction、ToLongBiFunction、DoubleToIntFunction、
DoubleToLongFunction、IntToDoubleFunction、LongToDoubleFunction、LongToIntFunction、ToDoubleBiFunction等;)
(Function的泛型有两个参数,T代表输入,R代表返回值;)
(Function的主要方法有apply、compose、andThen、identity;其中apply是唯一的抽象方法;)
(Consumer的扩展有BiConsumer、DoubleConsumer、IntConsumer、LongConsumer、ObjDoubleConsumer、ObjIntConsumer、ObjLongConsumer等;)
(Consumer的泛型只有一个参数,T代表输入;)
(Consumer的主要方法有accept、andThen;其中accept是唯一的抽象方法;)
(Supplier的扩展有BooleanSupplier、DoubleSupplier、IntSupplier、LongSupplier等;)
(Supplier的泛型只有一个参数,T代表输入;)
(Supplier只有一个方法get且是抽象方法;)
(Predicate的扩展有BiPredicate、DoublePredicate、IntPredicate、LongPredicate等;)
(Predicate的泛型只有一个参数,T代表输入;)
(Predicate的主要方法有test、and、negate、or、isEqual;其中test是唯一的抽象方法;)
(Operator有BinaryOperator、DoubleBinaryOperator、DoubleUnaryOperator、IntBinaryOperator、IntUnaryOperator、LongBinaryOperator、
LongUnaryOperator、UnaryOperator等;)
https://www.cnblogs.com/Dorae/p/7769868.html)
https://my.oschina.net/thinwonton/blog/2992371)
https://blog.youkuaiyun.com/ZYC88888/article/details/82622137(JDK1.8新特性Lambda表达式入门)
https://blog.youkuaiyun.com/ZYC88888/article/details/82624889(深入理解Java 8 Lambda)

java stream:
jdk8的stream(Collection)类似spark的RDD;
jdk8的stream中的方法类似spark的算子;
Stream、LongStream、IntStream、DoubleStream等接口都继承BaseStream接口;
(stream的惰性求值方法类似spark的transformation算子;及早求值方法类似spark的action算子;)
(stream的惰性求值有map、filter、flatMap、mapToInt、sorted、distinct、peek、limit、skip等;
及早求值有collect、count、reduce、max、min等;flatMap通常用于合并多个Collection;)
(其中短路操作有anyMatch、allMatch、noneMatch、findFirst、findAny、limit;)
(注意:max、min返回结果是java.util.Optional;)
(max、min中通常会有Integer::compareTo这种写法,也是jdk8的新特性,叫做方法引用;)
(Stream的并行化是指将数据分成块,为每块数据分配单独的处理单元;直接调用Stream.parallel方法即可;或者使用parallelStream并行流)
(注意:并行化只有在数据规模比较大或数据处理时间比较长的时候才能体现出优势;)
(Stream的并行操作依赖于Java7引入的Fork/Join框架?)
Collectors即收集器(java.util.stream.Collectors),用于将Stream转换为Set、Map、List等;
(Collectors常用方法有toCollection、toList、joining、summingInt、groupingBy、partitioningBy等;)
所有用作函数接口的接口都应该添加@FunctionalInterface注解,就像java.util.function包下的任意一个接口那样;
(java.lang.Runnable、java.util.concurrent.Callable、java.util.Comparator都是函数接口,都加了@FunctionalInterface,是jdk8加的;)
(对应的类或接口是java.lang.FunctionalInterface;)
(为啥每个函数接口只能有一个抽象方法?是的,如果有多个抽象方法,lambda语法无法实现;一个接口定义一个lambda行为)
(也叫做Single Abstract Method interfaces,即SAM Interfaces)
(函数接口中非抽象方法必须要加default!!!普通接口也必须加!!!这个default和注解的方法的default有什么区别?)
(jdk8的接口可以有具体的实现方法?是的,也可以是静态方法,但default和static不能同时出现;)
Stream像一个迭代器,单向且只能遍历一次;(内部迭代和链式调用)
Stream的方法可以分为四类:流到流之间的转换、流到终值的转换、直接遍历、构造流;
http://www.importnew.com/27901.html !!!)
java.util.stream定义了四种pipeline: DoublePipeline、IntPipeline、LongPipeline、ReferencePipeline;
(Pipeline是实现流式计算的流水线抽象,也是Stream的实现类;)

接口中的default方法是为了解决兼容性问题,比如Collection接口增加了stream方法,可以让老的代码不用修改;
(default方法有三条定律:一.类胜于接口,二.子类胜于父类,三.如果以上两条不适用,要么子类实现该方法,要么将该方法声明为抽象方法;)

java.util.stream.Collectors和java.util.stream.Collector:
Collector是接口,定义了supplier、accumulator、combiner、finisher、of、characteristics等方法;
(其中supplier是生成容器,accumulator是添加元素,combiner是合并容器,finisher是输出的结果;)
(同时定义了枚举Characteristics,代表是否有明确的finisher、是否需要同步、是否有序;)
https://my.oschina.net/joshuashaw/blog/487322)
Collectors是工具类,它的静态内部类CollectorImpl实现了Collector接口;
Collectors的toCollection、toList、toSet、toMap、joining、mapping、reducing、counting等方法返回的都是CollectorImpl即Collector类型;
(可以自己实现Collector接口来创建收集器,也可以用Collectors的这些现成方法,来创建并返回某个收集器;)

lambda表达式、java function、java stream三者关系:
lambda表达式最基础,可以直接为java function和java stream服务;
java function比java stream基础,前者只是接口,后者的方法实现全部依赖前者;
(当然,用户可以直接使用java function,而不使用java stream;)

柯里化是将多元函数分解为多个单元函数的多次调用的过程;
jdk1.8中,方法中可以定义内部类;
(其中一个例子是java.util.stream.MatchOps的makeRef、makeDouble、makeLong、makeInt方法;)

Optional、OptionalInt、OptionalDouble、OptionalLong:
https://my.oschina.net/thinwonton/blog/2992379
Optional的引入是为了解决方法返回null的问题;
(它是对T value的简单封装;当value为null时,就返回一个Optional<?> EMPTY对象;)
Optional主要方法有empty、get、isPresent、ifPresent、filter、map、flatMap、of、ofNullable、orElse、orElseGet、orElseThrow等;
OptionalInt、OptionalDouble、OptionalLong都是对Optional的扩展,它们的value是特定的类型如int、double、long;

FP如何影响设计模式和SOLID原则?

BaseStream.parallel、Collection.parallelStream是利用fork/join实现的?源码中整个过程是怎么调用的?

BaseStream.parallel的调用链:(以IntStream.range(0, 10000).parallel().forEach(list2::add)为例)
parallel().forEach -> IntPipeline H e a d . f o r E a c h − &gt; I n t P i p e l i n e . f o r E a c h − &gt; A b s t r a c t P i p e l i n e . e v a l u a t e − &gt; F o r E a c h O p s Head.forEach -&gt;IntPipeline.forEach -&gt; AbstractPipeline.evaluate -&gt; ForEachOps Head.forEach>IntPipeline.forEach>AbstractPipeline.evaluate>ForEachOpsForEachOp.evaluateParallel -> ForkJoinTask.invoke -> … -> ForEachOps.compute

Collection.parallelStream的调用链:(以val.parallelStream().mapToInt(i -> i).sum()为例,其中val= Arrays.asList(1,2,3);)
parallelStream().xxx.sum() -> IntPipeline.sum -> IntPipeline.reduce -> AbstractPipeline.evaluate ->ForEachOps$ForEachOp.evaluateParallel ->
ReduceTask -> …

FP如何影响并发代码的开发?是不是用了java stream,任何时候都不需要自己加锁和同步?
(加锁和同步是传统的、较为底层的编程方式,而java stream是高层API,最好不要混用;
一般不需要用户手动加锁;比如它依赖的ForkJoinTask就使用ReentrantLock实现了加锁和同步;)
(但是stream.parallel.forEach不能保证线程安全,可以通过加锁,或使用Stream的collect和reduce方法;)
https://www.cnblogs.com/puyangsky/p/7608741.html、 https://stackoverflow.com/questions/22350288/parallel-streams-collectors-and-thread-safety)
AbstractShortCircuitTask、AbstractTask、CountedCompleter、ForkJoinTask:
java.util.concurrent.CountedCompleter是ForkJoinTask的子类;用int pending字段记录直到结束需要完成多少任务;
CountedCompleter主要方法有onCompletion、compute、getPendingCount、setPendingCount、addToPendingCount、tryComplete、propagateCompletion、complete、firstComplete、nextComplete、quietlyCompleteRoot、helpComplete等;
AbstractTask是CountedCompleter的子类,主要方法是compute,要么直接计算,要么继续分割任务;
AbstractShortCircuitTask是AbstractTask的子类,主要方法也是compute,还有shortCircuit等其他方法;

MatchOps、SliceOps、FindOps、ForEachOps、ReduceOps、SortedOps、DistinctOps:

MatchOps是一个工厂类,用于短路匹配(匹配规则包括ANY、ALL、NONE),主要方法是makeRef、makeDouble、makeLong、makeInt等;
MatchOp是MatchOps的静态内部类,实现TerminalOp接口;
MatchTask是MatchOps的静态内部类,继承AbstractShortCircuitTask,最后被MatchOp以及makeXXX方法使用;

SliceOps也是一个工厂类,用于短路生成stream的子序列,主要方法是makeRef、makeDouble、makeLong、makeInt等;
SliceTask是SliceOps的静态内部类,继承AbstractShortCircuitTask接口,最后被makeXXX方法使用;

FindOps也是一个工厂类,基于短路原则查找stream中的元素;主要方法是makeRef、makeDouble、makeLong、makeInt等;
FindOp是FindOps的静态内部类,实现TerminalOp接口;
FindTask是FindOps的静态内部类,继承AbstractShortCircuitTask接口,最后被FindOp以及makeXXX方法使用;

ForEachOps也是一个工厂类,对stream每个元素执行action;主要方法是makeRef、makeDouble、makeLong、makeInt等;
ForEachOp是ForEachOps的静态内部类,实现TerminalOp接口;
ForEachTask、ForEachOrderedTask是ForEachOps的静态内部类,继承CountedCompleter接口,最后被ForEachOp以及makeXXX方法使用;
(其中ForEachTask、ForEachOrderedTask的区别是,是否有序)

ReduceOps也是一个工厂类,用于实现规约;主要方法是makeRef、makeDouble、makeLong、makeInt等;
ReduceOp是ReduceOps的静态内部类,实现TerminalOp接口;
ReduceTask是ReduceOps的静态内部类,继承AbstractTask接口,最后被ReduceOp以及makeXXX方法使用;

SortedOps也是一个工厂类,用于对stream进行排序;主要方法是makeRef、makeDouble、makeLong、makeInt等;
OfRef是SortedOps的静态内部类,实现ReferencePipeline.StatefulOp接口;
OfInt是SortedOps的静态内部类,实现IntPipeline.StatefulOp接口;
OfLong是SortedOps的静态内部类,实现LongPipeline.StatefulOp接口;
OfDouble是SortedOps的静态内部类,实现DoublePipeline.StatefulOp接口;
AbstractRefSortingSink、SizedRefSortingSink、RefSortingSink、AbstractIntSortingSink、SizedIntSortingSink、IntSortingSink、
AbstractLongSortingSink、SizedLongSortingSink、LongSortingSink、AbstractDoubleSortingSink、SizedDoubleSortingSink、
DoubleSortingSink等都是静态内部类;

DistinctOps也是一个工厂类,用于将stream变为无重复的流;主要方法是makeRef;

DoublePipeline、IntPipeline、LongPipeline、ReferencePipeline、AbstractPipeline、PipelineHelper:
AbstractPipeline是抽象类,继承PipelineHelper抽象类;
IntPipeline是AbstractPipeline的子类,并实现IntStream接口;
StatefulOp、StatelessOp、Head是IntPipeline的静态内部类,并继承IntPipeline;
DoublePipeline是AbstractPipeline的子类,并实现DoubleStream接口;
StatefulOp、StatelessOp、Head是DoublePipeline的静态内部类,并继承DoublePipeline;
LongPipeline是AbstractPipeline的子类,并实现LongStream接口;
StatefulOp、StatelessOp、Head是LongPipeline的静态内部类,并继承LongPipeline;
ReferencePipeline是AbstractPipeline的子类,并实现Stream接口;
StatefulOp、StatelessOp、Head是ReferencePipeline的静态内部类,并继承ReferencePipeline;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值