您的位置:首页 > 编程语言 > Java开发

java8函数式编程pdf

2018-01-05 15:54 399 查看


点击下载:Java8函数式编程pdf

java8函数式编程 pdf的重要性就不言而喻了吧。对于每一个JAVA开发者,这都是一个必过的坎。虽然现在的主流编程方式还是面向对象式。当然也不能否认这种方式的健壮性,可扩展性。但是随着编程技术的发展。走在时代前列的函数式编程就粉墨登场了。而这本java8函数式编程就全面介绍了函数式编程的精华,对于很多这种全新的编程理念,大家绝对有必要阅读学习一下。对于JAVA的发展道路非常的有帮助。而这本书主要围绕函数式编程理念、Lambda表达式、高级集合类和收集器、数据并行化等方向进行深入挖掘。对于有一点JAVA基础的朋友,仍然需要花点功夫进行深入学习。最后需要主要的是,本书面向的是JAVA
8版本。也是最新的成熟版本。它的最新特性就是Java 8 引入的一个核心概念是函数式接口。所以,想要赶上JAVA技术前沿的朋友,一定不要错过这本java8函数式编程。




图书简介

多年以来,函数式编程被认为是少数人的游戏,不适合推广给普罗大众。写作此书的目的就是为了挑战这种思想。本书将探讨如何编写出简单、干净、易读的代码;如何简单地使用并行计算提高性能;如何准确地为问题建模,并且开发出更好的领域特定语言;如何写出不易出错,并且更简单的并发代码;如何测试和调试Lambda表达式。
如果你已经掌握Java SE,想尽快了解Java 8新特性,写出简单干净的代码,那么本书不容错过。




函数式编程的核心思想

思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。类似于数学中的函数求值。
我们对这种思想的完全定义还为时尚早。我们现在想要的是如何通过使用函数式编程风格的代码来写出好代码。
本系列将讲述如何实用的使用函数式编程。帮助程序媛们(恩,没打错!!!)能写出易读、易维护的代码。


函数式编程的好处

减少了可变量(Immutable Variable)的声明
能够更好的利用并行(Parallelism)
代码更加简洁和可读
当然,Java 8中对于函数式编程风格的引入,并不是为了要颠覆已经根深蒂固面向对象编程风格。而是让它们和谐共处,取长补短。比如,使用面向对象对实体进行建模,对实体之间的关系进行表述;而使用函数式编码来实现实体中的各种状态改变,业务流程以及数据处理。


核心特色

声明式的代码风格(Declarative Style) : 这需要提高代码的抽象层次,比如在前面的例子中,将从集合中搜索一个元素的操作封装到contains方法中。
更多的不变性(Promote Immutability) : 能不声明变量就不要声明,需要变量时尽量使用final来修饰。因为变量越多,就意味着程序越难以并行。实现了不变性的方法意味着它不再有副作用,不会因为调用而改变程序的状态。
使用表达式来代替语句(Prefer Expression to Statement) : 使用语句也就意味着不变性的破坏和程序状态的改变,比如赋值语句的使用。
使用高阶函数(High-Order Function) : 在Java 8以前,重用是建立在对象和类型系统之上。而Java 8中则将重用的概念更进一步,使用函数也能够实现代码的重用。所谓高阶函数,不要被其名字唬住了,实际上很简单:
将函数作为参数传入到另外一个函数中
函数的返回值可以是函数类型
在函数中创建另一个函数


图书目录

前言
第1章 简介
 1.1为什么需要再次修改Java
 1.2什么是函数式编程
 1.3示例
第2章 Lambda表达式
 2.1第一个Lambda表达式
 2.2如何辨别Lambda表达式
 2.3引用值,而不是变量
 2.4函数接口
 2.5类型推断
 2.6要点回顾
 2.7练习
第3章 流
 3.1从外部迭代到内部迭代
 3.2实现机制
 3.3常用的流操作
  3.3.1collect(toList())
  3.3.2map
  3.3.3filter
  3.3.4flatMap
  3.3.5max和min
  3.3.6通用模式
  3.3.7reduce
  3.3.8整合操作
 3.4重构遗留代码
 3.5多次调用流操作
 3.6高阶函数
 3.7正确使用Lambda表达式
 3.8要点回顾
 3.9练习
 3.10进阶练习
第4章 类库
 4.1在代码中使用Lambda表达式
 4.2基本类型
 4.3重载解析
 4.4@FunctionalInterface
 4.5二进制接口的兼容性
 4.6默认方法
 4.7多重继承
 4.8权衡
 4.9接口的静态方法
 4.10Optional
 4.11要点回顾
 4.12练习
 4.13开放练习
第5章 高级集合类和收集器
 5.1方法引用
 5.2元素顺序
 5.3使用收集器
  5.3.1转换成其他集合
  5.3.2转换成值
  5.3.3数据分块
  5.3.4数据分组
  5.3.5字符串
  5.3.6组合收集器
  5.3.7重构和定制收集器
  5.3.8对收集器的归一化处理.
 5.4一些细节
 5.5要点回顾
 5.6练习
第6章 数据并行化
 6.1并行和并发
 6.2为什么并行化如此重要
 6.3并行化流操作
 6.4模拟系统
 6.5限制
 6.6性能
 6.7并行化数组操作
 6.8要点回顾
 6.9练习
第7章 测试、调试和重构
 7.1重构候选项
 7.1.1进进出出、摇摇晃晃
 7.1.2孤独的覆盖
 7.1.3同样的东西写两遍
 7.2Lambda表达式的单元测试
 7.3在测试替身时使用Lambda表达式
 7.4惰性求值和调试
 7.5日志和打印消息
 7.6解决方案:peak
 7.7在流中间设置断点
 7.8要点回顾
第8章 设计和架构的原则
 8.1Lambda表达式改变了设计模式
  8.1.1命令者模式
  8.1.2策略模式
  8.1.3观察者模式
  8.1.4模板方法模式
 8.2使用Lambda表达式的领域专用语言
  8.2.1使用Java编写DSL
  8.2.2实现
  8.2.3评估
 8.3使用Lambda表达式的SOLID原则
  8.3.1单一功能原则
  8.3.2开闭原则
  8.3.3依赖反转原则
 8.4进阶阅读
 8.5要点回顾
第9章 使用Lambda表达式编写并发程序
 9.1为什么要使用非阻塞式I/O
 9.2回调
 9.3消息传递架构
 9.4末日金字塔
 9.5Future
 9.6CompletableFuture
 9.7响应式编程
 9.8何时何地使用新技术
 9.9要点回顾
 9.10练习
第10章 下一步该怎么办


关于Java8函数式编程你需要了解的几点

函数式编程与面向对象的设计方法在思路和手段上都各有千秋,在这里,我将简要介绍一下函数式编程与面向对象相比的一些特点和差异。



1.函数作为一等公民
在理解函数作为一等公民这句话时,让我们先来看一下一种非常常用的互联网语言JavaScript,相信大家对它都不会陌生。JavaScript并不是严格意义上的函数式编程,不过,它也不是属于严格的面向对象。但是,如果你愿意,你既可以把它当做面向对象语言,也可以把它当做函数式语言,因此,称之为多范式语言,可能更加合适。
如果你使用jQuery,你可能会经常使用如下的代码: 
$("button").click(function(){  
  $("li").each(function(){  
    alert($(this).text())  
   });  
 });  
注意这里each()函数的参数,这是一个匿名函数,在遍历所有的li节点时,会弹出li节点的文本内容。将函数作为参数传递给另外一个函数,这是函数式编程的特性之一。
再来考察另外一个案例:
复制代码
function f1(){  
    var n=1;  
    function f2(){  
      alert(n);  
    }  
    return f2;  
  }  
var result=f1();  
result(); // 1  
复制代码
 这也是一段JavaScript代码,在这段代码中,注意函数f1的返回值,它返回了函数f2。在倒数第2行,返回的f2函数并赋值给result,实际上,此时的result就是一个函数,并且指向f2。对result的调用,就会打印n的值。
函数可以作为另外一个函数的返回值,也是函数式编程的重要特点。
2.无副作用
函数的副作用指的是函数在调用过程中,除了给出了返回值外,还修改了函数外部的状态,比如,函数在调用过程中,修改了某一个全局状态。函数式编程认为,函数的副用作应该被尽量避免。可以想象,如果一个函数肆意修改全局或者外部状态,当系统出现问题时,我们可能很难判断究竟是哪个函数引起的问题。这对于程序的调试和跟踪是没有好处的。如果函数都是显式函数,那么函数的执行显然不会受到外部或者全局信息的影响,因此,对于调试和排错是有益的。
注意:显式函数指函数与外界交换数据的唯一渠道就是参数和返回值,显式函数不会去读取或者修改函数的外部状态。与之相对的是隐式函数,隐式函数除了参数和返回值外,还会读取外部信息,或者可能修改外部信息。
然而,完全的无副作用实际上做不到的。因为系统总是需要获取或者修改外部信息的。同时,模块之间的交互也极有可能是通过共享变量进行的。如果完全禁止副作用的出现,也是一件让人很不愉快的事情。因此,大部分函数式编程语言,如Clojure等,都允许副作用的存在。但是与面向对象相比,这种函数调用的副作用,在函数式编程里,需要进行有效的限制。
申明式的(Declarative)
函数式编程是申明式的编程方式。相对于命令式(imperative)而言,命令式的程序设计喜欢大量使用可变对象和指令。我们总是习惯于创建对象或者变量,并且修改它们的状态或者值,或者喜欢提供一系列指令,要求程序执行。这种编程习惯在申明式的函数式编程中有所变化。对于申明式的编程范式,你不在需要提供明确的指令操作,所有的细节指令将会更好的被程序库所封装,你要做的只是提出你要的要求,申明你的用意即可。
请看下面一段程序,这一段传统的命令式编程,为了打印数组中的值,我们需要进行一个循环,并且每次需要判断循环是否结束。在循环体内,我们要明确地给出需要执行的语句和参数。
复制代码
public static void imperative(){  
         int[]iArr={1,3,4,5,6,9,8,7,4,2};  
         for(int i=0;i<iArr.length;i++){  
                   System.out.println(iArr[i]);  
         }  
}  
复制代码
与之对应的申明式代码如下: 
public static void declarative(){  
         int[]iArr={1,3,4,5,6,9,8,7,4,2};  
         Arrays.stream(iArr).forEach(System.out::println);  
}  
可以看到,变量数组的循环体居然消失了!println()函数似乎在这里也没有指定任何参数,在此,我们只是简单的申明了我们的用意。有关循环以及判断循环是否结束等操作都被简单地封装在程序库中。
3.尾递归优化
递归是一种常用的编程技巧。使用递归通常可以简化程序编码,大幅减少代码行数。但是递归有一个很大的弊病——它总是使用栈空间。但是,程序的栈空间是非常有限的,与堆空间相比,可能相差几个数量级(栈空间大小通常只有几百K,而堆空间则通常达到几百M甚至上百G)。因此,大规模的递归操作有可能发生栈空间溢出错误,这也限制了递归函数的使用,并给系统带来了一定的风险。
而尾递归优化可以有效地避免这种状况。尾递归指递归操作处于函数的最后一步。在这种情况下,该函数的工作其实已经完成(剩余的工作就是再次调用它自己),此时,只需要简单得将中间结果传递给后继调用的递归函数即可。此时,编译器就可以进行一种优化,使当前的函数调用返回,或者用新函数的帧栈覆盖老函数的帧栈。总之,当递归处于函数操作的最后一步时,我们总是可以想方设法避免递归操作不断申请栈空间。
大部分函数式编程语言直接或者间接支持尾递归优化。
4.不变模式
如果读者熟悉多线程程序设计,那么一定对不变模式有所有了解。所谓不变,是指对象在创建后,就不再发生变化。比如,java.lang.String就是不变模式的典型。如果你在Java中创建了一个String实例,无论如何,你都不可能改变整个String的值。比如,当你使用String.replace()函数试图进行字符串替换时,实际上,原有的字符串对象并不会发生变化,函数本身会返回一个新的String对象,作为给定字符替换后的返回值。不变的对象在函数式编程中被大量使用。
请看以下代码:
static int[] arr={1,3,4,5,6,7,8,9,10}; 
Arrays.stream(arr).map((x)->x=x+1).forEach(System.out::println); 
System.out.println(); 
Arrays.stream(arr).forEach(System.out::println); 
代码第2行看似对每一个数组成员执行了加1的操作。但是在操作完成后,在最后一行,打印arr数组所有的成员值时,你还是会发现,数组成员并没有变化!在使用函数式编程时,这种状态是一种常态,几乎所有的对象都拒绝被修改。
5.易于并行
由于对象都处于不变的状态,因此函数式编程更加易于并行。实际上,你甚至完全不用担心线程安全的问题。我们之所以要关注线程安全,一个很大的原因是当多个线程对同一个对象进行写操作时,容易将这个对象“写坏”,更专业的说法是“使得对象状态不一致”。但是,由于不变模式的存在,对象自创建以来,就不可能发生改变,因此,在多线程环境下,也就没有必要进行任何同步操作。这样不仅有利于并行化,同时,在并行化后,由于没有同步和锁机制,其性能也会比较好。读者可以关注一下java.lang.String对象。很显然,String对象可以在多线程中很好的工作,但是,它的每一个方法都没有进行同步处理。
6.更少的代码
通常情况下,函数式编程更加简明扼要,Clojure语言(一种运行于JVM的函数式语言)的爱好者就宣称,使用Clojure可以将Java代码行数减少到原有的十分之一。一般说来,精简的代码更易于维护。而Java代码的冗余性也是出了名的,大部分对于Java语言的攻击都会直接针对Java繁琐,而且死板的语法(但我认为这也是Java的优点之一,正如本书第一段提到的“保守的设计思想是Java最大的优势”),然而,引入函数式编程范式后,这种情况发生了改变。我们可以让Java用更少的代码完成更多的工作。
请看下面这个例子,对于数组中每一个成员,首先判断是否是奇数,如果是奇数,则执行加1,并最终打印数组内所有成员。
数组定义:
static int[] arr={1,3,4,5,6,7,8,9,10};  
传统的处理方式:  
for(int i=0;i<arr.length;i++){  
         if(arr[i]%2!=0){  
                   arr[i]++;  
         }  
         System.out.println(arr[i]);  
}  
使用函数式方式:
Arrays.stream(arr).map(x->(x%2==0?x:x+1)).forEach(System.out::println);
可以看到,函数式范式更加紧凑而且简洁。
函数式接口(Functional Interface)
为了在Java中引入函数式编程,Java 8中引入了函数式接口这一概念。
函数式接口就是仅声明了一个方法的接口,比如我们熟悉的Runnable,Callable,Comparable等都可以作为函数式接口。当然,在Java 8中,新添加了一类函数式接口,如Function,Predicate,Consumer,Supplier等。
在函数式接口中,可以声明0个或者多个default方法,这些方法在接口内就已经被实现了。因此,接口的default方法也是Java 8中引入的一个新概念。
函数式接口使用@FunctionalInterface注解进行标注。虽然这个注解的使用不是强制性的,但是使用它的好处是让此接口的目的更加明确,同时编译器也会对代码进行检查,来确保被该注解标注的接口的使用没有语法错误。
如果一个方法接受一个函数式接口作为参数,那么我们可以传入以下类型作为参数:
匿名内部类(Anonymous Inner Class)
Lambda表达式
方法或者构造器的引用(Method or Constructor Reference)
第一种方式是Java的以前版本中经常使用的方式,在Java 8中不再被推荐。 第二种方式中,Lambda表达式会被编译器转换成相应函数式接口的一个实例。 第三种方式会在后文中详细介绍。


免责声明:

来源于网络,仅用于分享知识,学习和交流!请下载完在24小时内删除。
禁用于商业用途!如果您喜欢《图解cio工作指南第4版》,请购买正版,谢谢合作。
爱学习,请到3322软件站查找资源自行下载!


下载说明:

方法一:
1、下载并解压,得出pdf文件
2、如果打不开本文件,别着急,这时候请务必在3322软件站选择一款阅读器下载哦
3、安装后,再打开解压得出的pdf文件
4、以上都完成后,接下来双击进行阅读就可以啦,朋友们开启你们的阅读之旅吧。
方法二:
1、可以在手机里下载3322软件站中的阅读器和百度网盘
2、接下来直接将pdf传输到百度网盘
3、用阅读器打开即可阅读




点击下载:Java8函数式编程pdf

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: