# java-practice-demo **Repository Path**: lovexiaona/java-practice-demo ## Basic Information - **Project Name**: java-practice-demo - **Description**: Java实战二书籍阅读,代码笔记 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-06 - **Last Updated**: 2021-08-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Java实战二 书籍阅读,代码笔记 ![封面](http://file.bixiao.xyz/img/image-20210806150706389.png "封面") ## 第一部分 ### 第1章 Java8,9,10以及11的变化 充分利用多核CUP: Java 8之前,只有通过多线程才能利用多个处理器核。 基于前文介绍的两个迫切需求(即编写更简洁的代码,以及更方便地利用处理器的多核): - Stream API; - 向方法传递代码的技巧; - 接口的默认方法。 Java 8提供了一个新的API(称为“流”,Stream),它支持多个数据处理的并行操作, 其思路和数据库查询语言类似——从高层的角度描述需求,而由“实现”(这里是Stream库)来选择底层最佳执行机制。 这样就可以避免用`synchronized`编写代码,这种代码不仅容易出错,而且在多核CPU2上执行所需的成本也比你想象的要高。 > **2**多核CPU的每个处理器核都有独立的高速缓存。加锁需要这些高速缓存同步运行,然而这又需要在内核间进行较慢的缓存一致性协议通信。 从修正的角度来看,在Java 8中加入Stream可以视为添加另外两项的直接原因:**向方法传递代码的简洁技巧**(方法引用、Lambda)和接口中的**默认方法**。 如果仅仅把“向方法传递代码”看成引入Stream的结果,就低估了它在Java 8中的应用范围。它提供了一种新的方式,能够简洁地表达**行为参数化**。 比方说,你想要写两个只有几行代码不同的方法,现在只需把不同的那部分代码作为参数传递进去就可以了。 #### 1.2.2 流处理 第一个编程概念是**流处理**。**流**是一系列数据项,一次只生成一项。程序可以从输入流中一个一个读取数据项,然后以同样的方式将数据项写入输出流。一个程序的输出流很可能是另一个程序的输入流。 > 就像汽车组装流水线一样,汽车排队进入加工站,每个加工站会接收、修改汽车,然后将之传递给下一站做进一步的处理。尽管流水线实际上是一个序列,但不同加工站的运行一般是并行的。 Java 8在`java.util.stream`中添加了一个Stream API。`Stream`就是一系列`T`类型的项目。你现在可以把它看成一种比较花哨的迭代器。Stream API的很多方法可以链接起来形成一个复杂的流水线,就像先前例子里面链接起来的Unix命令一样。 **好处:** * 现在你可以在一个更高的抽象层次上写Java 8程序了:**思路变成了把这样的流变成那样的流(就像写数据库查询语句时的那种思路)**,而不是一次只处理一个项目。 * Java 8可以透明地把输入的不相关部分拿到几个CPU核上去分别执行你的Stream操作流水线——这是**几乎免费**的并行,用不着去费劲搞`Thread`了。 #### 1.2.3 用行为参数化把代码传递给方法 Java 8中增加的另一个编程概念是通过API来传递代码的能力. Java 8增加了把方法(你的代码)作为参数传递给另一个方法的能力。我们把这一概念称为**行为参数化**。 #### 1.2.4 并行与共享的可变数据 **几乎免费的并行** 你提供的行为必须能够同时在不同的输入上**安全地执行**。一般情况下这就意味着,所写的代码不能访问共享的可变数据来完成它的工作。这些函数有时被称为“纯函数”“无副作用函数”或“无状态函数” 没有共享的可变数据,以及将方法和函数(即代码)传递给其他方法的能力,这两个要点是**函数式编程**范式的基石 在**命令式编程**范式中,你写的程序则是一系列改变状态的指令。“不能有共享的可变数据”意味着,一个方法可以通过它将参数值转换为结果的方式来完整描述,换句话说,它的行为就像一个数学函数,没有可见的副作用 #### 1.2.5 Java需要演变 Java 8中的主要变化反映了它开始远离常侧重改变现有值的经典面向对象思想,而向函数式编程领域转变。 #### 1.3 Java中的函数 编程语言中的**函数**一词通常是指**方法**,尤其是静态方法,这是在**数学函数**,也就是没有副作用的函数之外的一个新含义。 **编程语言的整个目的就在于操作值**,按照历史上编程语言的传统,这些值应被称为一等值(或一等公民) #### 代码传递例子 筛选绿色苹果,大于150g苹果 ##### 传统 * Apple ```java public class Apple { private int weight;//重量 private String color; //颜色 ///------get/set----------- } ``` * Service ```java package com.qing.demo1; import com.qing.demo1.Apple; import java.util.ArrayList; import java.util.List; public class AppleService { /** * 获取所有绿色的苹果 * @param apples * @return */ public static List filterGreenColor(List apples){ List result=new ArrayList<>(); for (Apple apple : apples) { if("green".equals(apple)){ result.add(apple); } } return result; } /** * 获取所有重量>150g的苹果 * @param apples * @return */ public static List filtersHeavyApple(List apples){ List result=new ArrayList<>(); for (Apple apple : apples) { if(apple.getWeight()>150){ result.add(apple); } } return result; } } ``` * Demo ```java package com.qing.demo1; import java.util.ArrayList; import java.util.List; public class Demo { public static List getApples(){ List appleList=new ArrayList<>(); appleList.add(new Apple(123,"green")); appleList.add(new Apple(156,"green")); appleList.add(new Apple(245,"green")); appleList.add(new Apple(345,"red")); appleList.add(new Apple(235,"red")); appleList.add(new Apple(100,"red")); appleList.add(new Apple(89,"red")); appleList.add(new Apple(98,"green")); appleList.add(new Apple(134,"yellow")); appleList.add(new Apple(345,"red")); appleList.add(new Apple(456,"yellow")); appleList.add(new Apple(567,"green")); appleList.add(new Apple(321,"yellow")); appleList.add(new Apple(89,"yellow")); appleList.add(new Apple(98,"green")); appleList.add(new Apple(79,"yellow")); appleList.add(new Apple(97,"yellow")); appleList.add(new Apple(45,"green")); return appleList; } public static void main(String[] args) { List appleList=getApples(); //获取所有绿色的苹果 AppleService.filterGreenColor(appleList).forEach(item->{ System.out.println(item.toString()); }); //获取所有重量>150的苹果 AppleService.filtersHeavyApple(appleList).forEach(item->{ System.out.println(item.toString()); }); } } ``` ##### 改进 * Apple ```java package com.qing.demo2; public class Apple { private int weight;//重量 private String color; //颜色 public static boolean isGreenApple(Apple apple){ return "green".equals(apple.getColor()); } public static boolean isHeavyApple(Apple apple){ return apple.getWeight()>150; } //-------------get/set------------ } ``` * Predicate 断定性接口 ```java package com.qing.demo2; /** * 自定义断定性接口 * @param */ public interface Predicate { boolean test(T t); } ``` * Service ```java package com.qing.demo2; import java.util.ArrayList; import java.util.List; public class AppleService2 { /** * 苹果方法过滤 * @param apples * @param p * @return */ public static List filterApples(List apples,Predicate p){ List result=new ArrayList<>(); for (Apple apple : apples) { if(p.test(apple)){ result.add(apple); } } return result; } } ``` * Demo ```java package com.qing.demo2; import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class Demo { public static List getApples(){ List appleList=new ArrayList<>(); appleList.add(new Apple(123,"green")); appleList.add(new Apple(156,"green")); appleList.add(new Apple(245,"green")); appleList.add(new Apple(345,"red")); appleList.add(new Apple(235,"red")); appleList.add(new Apple(100,"red")); appleList.add(new Apple(89,"red")); appleList.add(new Apple(98,"green")); appleList.add(new Apple(134,"yellow")); appleList.add(new Apple(345,"red")); appleList.add(new Apple(456,"yellow")); appleList.add(new Apple(567,"green")); appleList.add(new Apple(321,"yellow")); appleList.add(new Apple(89,"yellow")); appleList.add(new Apple(98,"green")); appleList.add(new Apple(79,"yellow")); appleList.add(new Apple(97,"yellow")); appleList.add(new Apple(45,"green")); return appleList; } public static void main(String[] args) { List appleList=getApples(); // getFilterApples1(appleList); // getFilterApples2(appleList); // getFilterApples3(appleList); getFilterApples4(appleList); } /** * 使用自定义断言接口 * @param appleList */ public static void getFilterApples1(List appleList){ //获取所有的绿色苹果 AppleService2.filterApples(appleList, new Predicate() { @Override public boolean test(Apple apple) { return Apple.isGreenApple(apple); } }).forEach(item->{ System.out.println(item.toString()); }); System.out.println("-------------------"); //获取所有>150g的苹果 AppleService2.filterApples(appleList,new Predicate(){ @Override public boolean test(Apple apple) { return Apple.isHeavyApple(apple); } }).forEach(item->System.out.println(item)); } public static void getFilterApples2(List appleList){ //获取所有的绿色苹果 AppleService2.filterApples(appleList,(apple) ->{ return Apple.isGreenApple(apple); }).forEach(item->{ System.out.println(item.toString()); }); System.out.println("-------------------"); //获取所有>150g的苹果 AppleService2.filterApples(appleList,(apple)-> { return Apple.isHeavyApple(apple); }).forEach(item->System.out.println(item)); } public static void getFilterApples3(List appleList){ //获取所有的绿色苹果 AppleService2.filterApples(appleList,(apple) ->Apple.isGreenApple(apple)).forEach(item->{ System.out.println(item.toString()); }); System.out.println("-------------------"); //获取所有>150g的苹果 AppleService2.filterApples(appleList,(apple) -> Apple.isHeavyApple(apple)).forEach(item->System.out.println(item)); } public static void getFilterApples4(List appleList){ //获取所有的黄色苹果 AppleService2.filterApples(appleList,(apple)->"red".equals(apple.getColor())).forEach(item->{ System.out.println(item.toString()); }); System.out.println("-------------------"); //获取所有>200g的苹果 AppleService2.filterApples(appleList,(apple -> apple.getWeight()>200)).forEach(item->System.out.println(item)); } public static void getFilterApples5(List appleList){ //获取所有的绿色苹果 AppleService2.filterApples(appleList,Apple::isGreenApple).forEach(item->{ System.out.println(item.toString()); }); System.out.println("-------------------"); //获取所有>150g的苹果 AppleService2.filterApples(appleList,Apple::isHeavyApple).forEach(item->System.out.println(item)); } } ``` #### 1.4 流 Stream API处理数据的方式与Collection API不同。 用集合的话,你得自己管理迭代过程。你得用`for-each`循环一个个地迭代元素,然后再处理元素。我们把这种数据迭代方法称为**外部迭代**。 相反,有了Stream API,你根本用不着操心循环的事情。数据处理完全是在库内部进行的。我们把这种思想叫作**内部迭代**。 > Java 8基于`Stream`的并行提倡很少使用`synchronized`的函数式编程风格,它关注`数据分块`而不是协调访问。 **Collection主要是为了存储和访问数据,Stream则主要用于描述对数据的计算。** 这里的关键点在于,Stream API允许并提倡并行处理一个Stream中的元素。虽然乍看上去可能有点儿怪,但筛选一个Collection(将上一节的`filterApples`应用在一个`List`上)的最快方法常常是将其转换为Stream,进行并行处理,然后再转换回`List` ```java public static void main(String[] args) { List apples=getApples(); //顺序处理 Long startTime1=System.currentTimeMillis(); List heavyApples=apples.stream().filter(a->a.getWeight()>150).filter(a->a.getColor().equals("green")).collect(Collectors.toList()); System.out.println(System.currentTimeMillis()-startTime1); //并行处理 Long startTime2=System.currentTimeMillis(); List heavyApples2=apples.parallelStream().filter(a->a.getWeight()>150).filter(a->a.getColor().equals("green")).collect(Collectors.toList()); System.out.println(System.currentTimeMillis()-startTime2); System.out.println(heavyApples); System.out.println(heavyApples2); } ``` ```java 62 4 [Apple{weight=156, color='green'}, Apple{weight=245, color='green'}, Apple{weight=567, color='green'}] [Apple{weight=156, color='green'}, Apple{weight=245, color='green'}, Apple{weight=567, color='green'}] ``` **Java中的并行与无共享可变状态** 大家都说在Java中并行很难,而且和`synchronized`相关的“玩意儿”都容易出问题。那Java 8里面有什么“灵丹妙药”呢?事实上有两个。 首先,**库会负责分块,即把大的流分成几个小的流,以便并行处理。** 其次,流提供的这个几乎免费的并行,只有在传递给`filter`之类的库方法的方法不会互动(比方说有可变的共享对象)时才能工作。但是其实这个限制对于程序员来说挺自然的,比如`Apple::isGreenApple`就是这样。确实,虽然**函数式编程**中的**函数**的主要意思是“把函数作为一等值”,但它也常常隐含着第二层意思,即“执行时在元素之间无互动”。 #### 1.5 默认方法及Java模块 Java 9提供了模块系统,允许你通过语法定义由一系列包组成的**模块**——通过它你能更好地控制命名空间和包的可见性。模块对简单的类JAR组件进行了增强,使其具备了结构,既能作为用户文档,也能由机器进行检查 Java 9提供了模块系统,允许你通过语法定义由一系列包组成的**模块**——通过它你能更好地控制命名空间和包的可见性。模块对简单的类JAR组件进行了增强,使其具备了结构,既能作为用户文档,也能由机器进行检查 #### 1.6 来自函数式编程的其他好思想 > Java从函数式编程引入的两个核心思想:将方法和Lambda作为一等值,以及在没有可变共享状态时,函数或方法可以有效、安全地并行执行。这两种思想新的Stream API都用到了。 Java 8提供了一个`Optional`类,如果你能一致地使用它,就能帮助你避免出现`NullPointerException`。这是一个容器对象,它既可以包含值,也可以不包含值。`Optional`提供了方法来明确地处理值不存在的情况,这样就可以避免`NullPointerException`了。换句话说,它通过类型系统,允许你表明一个变量可能缺失值。 第二个思想是**(结构化的)模式匹配** > 这个术语有两个意思,这里指的是数学和函数式编程中的意思,即函数是分情况定义的,而不是使用`if-then-else`。它的另一个意思类似于“在给定目录中找到所有类似于IMG*.JPG形式的文件”,和所谓的正则表达式有关。 不幸的是,Java 8并不完全支持模式匹配 **消除`if-then-else`或`switch`** **状态模式** Java中,你可以使用`if-then-else`或`switch`语句表达同样的语义。其他语言已经证实,对于更复杂的数据类型,在表达编程思想时,使用模式匹配比`if-then-else`更简明。你也可以采用多态和方法重写替代`if-then-else`来处理这种类型的数据,但是,到底哪种方式更适合,在语言设计上仍然有很多争论 ### 第 2 章 通过行为参数化传递代码 **行为参数化**就是可以帮助你处理频繁变更的需求的一种软件开发模式。一言以蔽之,它意味着拿出一个代码块,把它准备好却不去执行它。这个代码块以后可以被你程序的其他部分调用,这意味着你可以推迟这块代码的执行。例如,你可以将代码块作为参数传递给另一个方法,稍后再去执行它。这样,这个方法的行为就基于那块代码被参数化了。例如,如果你要处理一个集合,可能会写一个方法: - 可以对列表中的每个元素做“某件事”; - 可以在列表处理完后做“另一件事”; - 遇到错误时可以做“另外一件事”。 **行为参数化**说的就是这个。