java函数式编程
JAVA如果真的这么完美无缺,那为什么还会有其他语言的兴盛呢?所以说,没有一样东西是绝对完美的,JDK8包括之后的版本,就是不断的完善JAVA语言,让它往更好的方向上去走,面向过程有它的缺点,然而无疑也有它的优点,在JAVA8 之前,JAVA欠缺了高效的并行操作,写一个并行程序代码往往是费事费力又不讨好,然而在JAVA8之上,只需要简单的修改几行代码,就可以让代码在多核CPU上完美运行,所以为了达到这个效果,编写这样的JDK类库,就需要在语言层次上修改现有的JAVA,因此,在JAVA中增加Lambda表达式就是刻不容缓的任务了--事实上在2011年的JDK7版本中预计就要引入Lambda,但是因为种种原因,计划最终推迟到了2014年的JDK8。
为了达到高效操作集合类,实现并行计算或者操作的目的,你得要学习来自JDK8的新的语法,并且要从面相对象编程的局限中稍微跳出来一些,但是比起之前手写一大段代码,我觉得这样的学习是十分值得也是十分必要的,节省了时间与成本,同时也更不容易出错!站在巨人的肩膀上,这是任何一个人都需要借鉴的方法,为什么每次JDK版本的变更都历时几年?oracle的工程师并不是傻瓜,尤其是在编写JDK类库上,借用他人的代码并不是可耻的行为,新的代码更加高效,并且更让人容易阅读,这种新代码更加关注的它所实现的业务逻辑,而并非实现机制,所以你看即使是引入了Lambda,从某种意义上来说,这依旧是面向对象的一种实现方法--关注的并非实现机制,这样的代码更容易维护,也更不容易出错。
B. java8 函数式编程和lambda的区别
很多编程语言早就引入了Lambda表达式而java语法又比较繁琐,被很多人嫌弃.于是java8新增了特性支持Lambda表达式.例如:不用Lambda表达式写的匿名内部类List names = Arrays.asList("jack", "tom", "jerry");Collections.sort(names, new Comparator() { @Override public int compare(String s1, String s2) { return s2.compareTo(s1); }});采用Lambda表达式简化上面的代码List names = Arrays.asList("jack", "tom", "jerry");Collections.sort(names, (s1, s2) -> s2.compareTo(s1));当然了java8中Lambda表达式还有其他用法,但我比较喜欢它的简洁
C. java8 函数式编程是什么
java8完全颠覆我们对java的认识了 函数式编程里面有一点就是 把一段函数当作是一个参数来进行传递
D. Java8的函数式编程怎么样
使用函数式代码的好处:
减少了可变量(Immutable Variable)的声明
能够更好的利用并行(Parallelism)
代码更加简洁和可读
函数式接口
函数式接口就是仅声明了一个方法的接口,比如我们熟悉的Runnable,Callable,Comparable等都可以作为函数式接口。当然,在Java 8中,新添加了一类函数式接口,如Function,Predicate,Consumer,Supplier等。
E. 求java8函数式编程pdf
java8完全颠覆我们对java的认识了函数式编程里面有一点就是把一段函数当作是一个参数来进行传递
F. 为什么函数式编程在Java中很危险
在许多的项目中,纯函数编程,会造成一片混乱 。。。。。。。。。。
G. 函数式编程(Functional Programming)相比面向对象编程(Object
函数作为一等公民和 closure capture 好处大家都知道, 传统语言都在想方设法集成这些特性. map, filter, rece 等等东西写代码处理集合真是非常舒爽, 一眼就能看懂干什么, 又不用担心循环中的边界条件.
- 函数式语言中的另一个利器是 pattern match, 很多费脑子的复杂操作一下就搞定了... 为什么 Thinking in Java 这么大这么厚一本书, 学完了你基本干不了啥事情? 因为在 Java 的思维世界里, 你要和概念的海洋作斗争, 而命名恰恰就是编程的两大难题之一. 如果有 pattern match, 哪用想这么多没意义的中间变量名?
- 什么是 immutability? 其实细分起来有语法上的 immutable (例如 Java 里的 final 关键字), 和运行时对象的 immutable (一个变量名可以修改指向不同对象, 但对象的内容不可变). 两者的联系是: 如果语法上规定所有变量都是 "final" 的, 那么运行时对象就相当于都 immutable 了. 但如果语法上部分变量是 final, 部分不是, 那么就不能得出运行时对象全都 immutable 的结论.
而在运行时对象都是 immutable 的情形下, 很多优势才会显现出来.
- "immutability 会拖慢程序" 略扯淡, 应用了 immutability 的 VM 实现可以去掉很多情况的 lock, 并发处理速度会更快.
就算不是并发处理的情况, 如果所有对象都 immutable, 手动的保护性拷贝都可以去掉, 处理复杂业务会更简单快速.
其实编译器可以把很多 immutable 的操作改写成 mutable 的操作, RAM 能不能擦写没什么影响的. LLVM 中间语言就是个变量名 immutable 的语言, 但是编译出来的代码效率很高 --- 编译器就是这么贱, 你明明为了提高性能重复利用同一个变量, 但是它却偏偏要先把你写的单个变量改成多个变量单次赋值再去做优化...
对象实例 immutable 了 GC 能更简化. 因为只有新对象指向老对象, 老对象不能指向新对象, 对实现分代 GC 的人来说真是一个天堂! Haskell 和 Erlang 的分代 GC 实现都不复杂而且效率很高 (但 Clojure 因为是 JVM 上的二奶语言享受不到这个优惠, Scala 不是所有对象都 immutable, 只能起用接口限制程序员的效果了...)
在 immutable 的环境里还有什么好处? 就是没有环引用! 不用做环检测不用加弱引用, 那引用计数还不爽翻了? 是的... 有人用引用计数实现 Erlang 的, 写得非常爽... 我也在写一个语言, 所有变量 immutable, 就用引用计数做内存管理, 当引用数为 1 的时候还能做 destructive update, 节省一次内存分配释放, 也不损害 immutable 的语义哦 (巨坑中, stay tuned...).
immutable 的环境还能轻易实现 debug step back. 至今大部分语言和环境的 debugger 都没有后退功能, 而后退功能的实现难点主要是要保存对象变化的历史记录, mutable 的对象系统就得复制或者深复制对象才能恢复历史. 而 immutable 的环境里, 只要保留之前的对象的引用, 就能直接恢复.
immutability 至今表现还不太好的地方是哈希表, 例如 Haskell 的哈希表实现就一片混乱... 如果要实现一个高效的 immutable 并且保持插入顺序的哈希表... 你会比较蛋疼. 现在做得比较好的是 HAMT 或者 RRB tree, 但也没有 mutable 的哈希表快.
- immutable 会造成代码比较难写吗? 事实上就是思维方式要改变, 用更高阶的操作就好了, 然后你会发现经常变得更好写了. 而且 state monad + do notation 可以让你退回去用 mutable 的思维方式想问题, 而且, 这个 state 是严格控制在 local 的不会搅乱你其他部分的程序.
如果所有对象都 immutable, 那程序根本就没有传值和传引用的区别了, 学习起来更简单, 语义更一致 (但一心要当大杂烩的 Scala 反而变得很复杂...)
- 组件和对象会不会比 immutable 更适合 GUI 编程? 现状是 functional language 在 GUI 库上面还不够成熟, 但应用 functional 概念架构的 GUI 反而速度更快更稳定, 在 web 前端框架上面已经逐渐体现了, 例如 swannodette/om · GitHub 和 Raynos/mercury · GitHub. 用 Om 实现一个历史后退的功能真的清爽容易到了极点.
- 函数式语言中常用的 list 也受限于当前的 CPU 架构体系, locality 没有 array 好, 不过很多 list 中使用的 idiom 也可以直接应用到 array 上, 问题不大.
- 某些面向对象的方法论使用大量的隐喻, 使得不懂的人都可以以为自己懂了, 也许才是其最重要的优势吧.
H. 什么是函数式编程思维
1.表达式化
在
最初的时候,需要转变观念,去可变量,去循环,把命令式改成表达式,注意,这只是把你丢在荒山野岭让你感受一下,离开熟悉的环境,地球依然在转,但是有个
重点,那就是一切都是表达式; 为什么是表达式呢?这个问题就像为什么鱼在水里?
因为函数式建立在lambda演算之上而非图灵机,只不过两者被证明等价,所以你可以在你的机器上跑全是表达式的代码,就如有人证明天空适合鱼生存,所以
鱼可以在天上游
当你接受了鱼可以在天上游之后,就该上正餐了
1.5 数据与行为分离
这也是和面向对象不一致的地方,面向对象强调数据与行为绑定,但函数式不是,确切的说函数式 函数与数据等价,所以你才可以将函数当参数与返回值,你在设计时,切勿让数据自己长腿能跑,其次,行为必须消除副作用,不可以偷偷把数据改了,习惯第一条后,应该不会的
2.高阶逻辑
用
了函数式,就不要在想循环,赋值这些低阶逻辑了,而应该更高阶的思考问题,这比转化表达式更难,函数式又叫声明式,也就是你要做什么,只要说一下就行,而
非写个遍历,做个状态判断,用函数式你不需要考虑这些,你不知道函数式的列表是怎么遍历的,中间向两边?
从后往前?这也是为何函数式适合并发的原因之一,你想知道列表中大于3的数有多少,只要,list.count(_ > 3)
而不是写循环,你可以直接写你的业务,不要拘泥于细节,有点像sql, 你需要什么告诉电脑就行,你或许会问,count foreach filter
这些函数怎么来的? 因为有了他们你才不需要写循环,他们把你留在高阶逻辑中,这个问题的答案请看下面
3.组合子逻辑 或又叫 自底向上的设计
函
数式和OO是反的,面向对象是自顶向下的设计,函数式是自底向上的设计,也就是先定义最基本的操作,然后不断组合,不断堆积以满足你的所有需要,如sql
定义了select, from, where...这几个组合子,来满足你的查询需求,同理函数式语言会提供foreach,
map等组合子(操作)来满足你的需求,所以你必须自下而上的设计你的代码结构,并且满足你的需求,当你只用组合子写代码时,你会发现你写的全是高阶逻辑
如
果这些已有组合子满足不了你,你就得自己写,foreach不行,你就自己写递归,我告诉你,递归背后也是组合子,这里一些'大神'应该不知道,在图灵机
里,递归就是方法不断调用自己没什么好说的,但是在lambda演算中,匿名函数是没法调用自己的,所以递归是用Y组合子(又叫不动点组合子)把递归函数
自己求解出来再调用的,这才可以实现递归,并与图灵机的循环等价,有点跑题了,总之要想顺手的写函数式,最好用面向组合子的设计,注意,不是必须,组合子
演算和lambda演算可以相互转化,也就是,你完全可以写一堆杂乱的表达式,但没有组合子逻辑来得清爽,Haskell大规模使用monad这个特殊组
合子,始其变得统一整洁
好了,总结一下
函数式思维,其实就是组合子逻辑,用简单的几个函数组合来构建复杂逻辑,始终以高阶的角度去表达问题,而非依赖副作用。
知道这点,你用java也可以写函数式代码了
I. Java函数式编程语言是什么
函数式编程语言的核心是它以处理数据的方式处理代码。这意味着函数应该是第一等级(First-class)的值,并且能够被赋值给变量,传递给函数等等。
事实上,很多函数式语言比这走得更远,将计算和算法看得比它们操作的数据更重要。其中有些语言想分离程序状态和函数(以一种看起来有点对立的方式,使用面向对象的语言,这通常会将它们联系得更紧密)。
Clojure编程语言就是一个这样的例子,尽管它运行于基于类的Java虚拟机,Clojure的本质是函数式语言,并且在高级语言源程序中不直接公布类和对象(尽管提供了与Java良好的互操作性)。
J. java 为什么引入函数式接口而不是委托
一、Lambda表达式Lambda表达式可以说是Java 8最大的卖点,她将函数式编程引入了Java。Lambda允许把函数作为一个方法的参数,或者把代码看成数据。一个Lambda表达式可以由用逗号分隔的参数列表、–符号与函数体三部分表示。例如:Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e - System.out.println( e ) ); 1 Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e - System.out.println( e ) ); 为了使现有函数更好的支持Lambda表达式,Java 8引入了函数式接口的概念。函数式接口就是只有一个方法的普通接口。java.lang.Runnable与java.util.concurrent.Callable是函数式接口最典型的例子。为此,Java 8增加了一种特殊的注解@FunctionalInterface:1 @FunctionalInterface2 public interface Functional {3 void method();4 }二、接口的默认方法与静态方法我们可以在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现。例如:1 public interface DefaultFunctionInterface {2 default String defaultFunction() {3 return "default function";4 }5 }我们还可以在接口中定义静态方法,使用static关键字,也可以提供实现。例如:1 public interface StaticFunctionInterface {2 static String staticFunction() {3 return "static function";4 }5 }接口的默认方法和静态方法的引入,其实可以认为引入了C++中抽象类的理念,以后我们再也不用在每个实现类中都写重复的代码了。三、方法引用通常与Lambda表达式联合使用,可以直接引用已有Java类或对象的方法。一般有四种不同的方法引用:构造器引用。语法是Class::new,或者更一般的Class T ::new,要求构造器方法是没有参数;静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;特定类的任意对象方法引用。它的语法是Class::method。要求方法是没有参数的;特定对象的方法引用,它的语法是instance::method。要求方法接受一个参数,与3不同的地方在于,3是在列表元素上分别调用方法,而4是在某个对象上调用方法,将列表元素作为参数传入;四、重复注解在Java 5中使用注解有一个限制,即相同的注解在同一位置只能声明一次。Java 8引入重复注解,这样相同的注解在同一地方也可以声明多次。重复注解机制本身需要用@Repeatable注解。Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。五、扩展注解的支持Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。六、OptionalJava 8引入Optional类来防止空指针异常,Optional类最先是由Google的Guava项目引入的。Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了。七、StreamStream API是把真正的函数式编程风格引入到Java中。其实简单来说可以把Stream理解为MapRece,当然Google的MapRece的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了,非常酷帅!八、Date/Time API (JSR 310)Java 8新的Date-Time API (JSR 310)受Joda-Time的影响,提供了新的java.time包,可以用来替代 java.util.Date和java.util.Calendar。一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的。九、JavaScript引擎NashornNashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。十、Base64在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。除了这十大新特性之外,还有另外的一些新特性:更好的类型推测机制:Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。编译器优化:Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。并行(parallel)数组:支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。并发(Concurrency):在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。Nashorn引擎jjs:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。类依赖分析器jdeps:可以显示Java类的包级别或类级别的依赖。JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)。