Java设计模式

This commit is contained in:
罗祥 2019-12-12 13:51:16 +08:00
parent e6d6fa7fd7
commit dff4e5e84c
6 changed files with 18 additions and 10073 deletions

View File

@ -1,20 +1,15 @@
# :coffee: JAVA
- Java 基础
- GOF 23 种设计模式
- 深入理解 Java 虚拟机
- 网络编程原理
- Netty 编程模式
+ [Java 反射与注解](notes/Java_反射与注解.md)
+ [Java 并发编程](notes/Java_并发.md)
+ [Java 设计模式](notes/Java_设计模式.md)
+ 深入理解 Java 虚拟机
## 💻 前端基础
- JavaScript 基础
- 原型与原型链,作用域与闭包,异步与单线程
- [JavaScript 基础](notes/JavaScript_基础.md)
- ECMAScript 6.0 基础
- WebPack 基础
- Vue 核心概念
@ -51,64 +46,32 @@
+ [Linux 常用 Shell 命令](notes/Linux_常用Shell命令.md)
+ [Docker 基础](notes/Docker_基础.md)
## 🌳 Spring 系列
### Spring
+ Spring事务机制、事务的传播与监控
### Spring Cloud
- Eureka 服务的注册和发现
- Eureka 高可用集群搭建
- Ribbon 客户端负载均衡RestTemplate 服务远程调用
- OpenFeign 声明式服务调用,服务容错处理
- Hystix 服务容错保护Hystrix Dashboard 断路器监控Turbine 断路器聚合监控
- Zuul 网关服务
- Sleuth + Zipkin 服务链路追踪
- Config 分布式配置中心 ,集成 Bus 消息总线实现配置热更新
### 分布式解决方案
+ 全局 ID 生成方案
+ 分布式 Session 解决方案
+ 分布式锁解决方案
+ 分布式事务解决方案实战
## 常用技术栈
### Kafka
1. [Kafka 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka简介.md)
2. [基于 Zookeeper 搭建 Kafka 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
3. [Kafka 生产者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka生产者详解.md)
4. [Kafka 消费者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka消费者详解.md)
5. [深入理解 Kafka 副本机制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka深入理解分区副本机制.md)
+ [Kafka 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka简介.md)
+ [基于 Zookeeper 搭建 Kafka 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
+ [Kafka 生产者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka生产者详解.md)
+ [Kafka 消费者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka消费者详解.md)
+ [深入理解 Kafka 副本机制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka深入理解分区副本机制.md)
### RabbitMQ
- [RabbitMQ 核心概念](notes/RabbitMQ_基础.md)
- [RabbitMQ 客户端开发](notes/RabbitMQ_客户端开发.md)
- [基于 HAProxy + KeepAlived 搭建 RabbitMQ 高可用集群](notes/RabbitMQ_高可用集群架构.md)
+ [RabbitMQ 核心概念](notes/RabbitMQ_基础.md)
+ [RabbitMQ 客户端开发](notes/RabbitMQ_客户端开发.md)
+ [基于 HAProxy + KeepAlived 搭建 RabbitMQ 高可用集群](notes/RabbitMQ_高可用集群架构.md)
### ZooKeeper
1. [ZooKeeper 简介及核心概念](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper简介及核心概念.md)
2. [ZooKeeper 单机环境和集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Zookeeper单机环境和集群环境搭建.md)
3. [ZooKeeper 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper常用Shell命令.md)
4. [ZooKeeper Java 客户端 —— Apache Curator](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_Java客户端Curator.md)
5. [ZooKeeper ACL 权限控制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_ACL权限控制.md)
+ [ZooKeeper 简介及核心概念](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper简介及核心概念.md)
+ [ZooKeeper 单机环境和集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Zookeeper单机环境和集群环境搭建.md)
+ [ZooKeeper 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper常用Shell命令.md)
+ [ZooKeeper Java 客户端](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_Java客户端Curator.md)
+ [ZooKeeper ACL 权限控制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_ACL权限控制.md)
### Nginx
- [Nginx 基础之静态网站部署,负载均衡,动静分离](notes/Nginx_基础.md)
## 📊 算法
TODO

View File

@ -1,612 +0,0 @@
# 《Java 8 实战》读书笔记
## 目录<br/>
<a href="#第二部分-函数式数据处理">第二部分 函数式数据处理</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#第4章-引入流">第4章 引入流</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1流的基本使用">1.流的基本使用</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2数值流">2.数值流</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#3构建流">3.构建流</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#第5章-使用流">第5章 使用流</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1中间操作和基本操作">1.中间操作和基本操作</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2flatMap的使用">2.flatMap的使用</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#3归约">3.归约</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#第6章-用流收集数据">第6章 用流收集数据</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1预定义收集器">1.预定义收集器</a><br/>
<a href="#第三部分-高效的Java-8编程">第三部分 高效的Java 8编程</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#第12章-新的日期和时间API">第12章 新的日期和时间API</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#121-LocalDate、LocalTime、Instant、Duration、period">12.1 LocalDate、LocalTime、Instant、Duration、period</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1使用-LocalDate-和-LocalTime">1.使用 LocalDate 和 LocalTime</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2使用LocalDateTime">2.使用LocalDateTime</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#3时间间隔-Duration-或-Period">3.时间间隔 Duration 或 Period</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#122-操纵、解析和格式化日期">12.2 操纵、解析和格式化日期</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1操纵日期加减">1.操纵日期加减</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2使用TemporalAdjusters">2.使用TemporalAdjusters</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#3日期格式解析">3.日期格式解析</a><br/>
## 正文<br/>
## 第二部分 函数式数据处理
### 第4章 引入流
#### 1.流的基本使用
```java
// 基础数据类
public class Data {
public enum Type {MEAT, FISH, OTHER}
public static List<Dish> menu = Arrays.asList(
new Dish("pork", false, 800, Type.MEAT),
new Dish("beef", false, 700, Type.MEAT),
new Dish("chicken", false, 400, Type.MEAT),
new Dish("french fries", true, 530, Type.OTHER),
new Dish("rice", true, 350, Type.OTHER),
new Dish("season fruit", true, 120, Type.OTHER),
new Dish("pizza", true, 550, Type.OTHER),
new Dish("prawns", false, 300, Type.FISH),
new Dish("salmon", false, 450, Type.FISH));
static class Dish {
private final String name;
private final boolean vegetarian;
private final int calories;
private final Data.Type type;
public Dish(String name, boolean vegetarian, int calories, Data.Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Data.Type getType() {
return type;
}
@Override
public String toString() {
return name;
}
}
}
```
```java
// 流的使用
public class Stream {
public static void main(String[] args) {
List<String> collect = Data.menu.stream().filter(d -> d.getCalories() > 300).map(Data.Dish::getName).limit(3).collect(Collectors.toList());
collect.forEach(System.out::println);
}
}
```
#### 2.数值流
**映射到数值流(mapToInt)**
```java
public class Stream {
public static void main(String[] args) {
//得到的是 Stream<Integer>
java.util.stream.Stream<Integer> integerStream = Data.menu.stream().map(Data.Dish::getCalories);
Integer reduce = integerStream.reduce(0, Integer::sum);
System.out.println(reduce); //4200
//得到的是 IntStream
IntStream intStream = Data.menu.stream().mapToInt(Data.Dish::getCalories);
int sum = intStream.sum();
System.out.println(sum); //4200
}
}
```
**数值流到映射(boxed)**
```java
public class Stream {
public static void main(String[] args) {
//得到的是 Stream<Integer>
java.util.stream.Stream<Integer> integerStream = Data.menu.stream().map(Data.Dish::getCalories);
Integer reduce = integerStream.reduce(0, Integer::sum);
System.out.println(reduce); //4200
//得到的是 IntStream
IntStream intStream = Data.menu.stream().mapToInt(Data.Dish::getCalories);
java.util.stream.Stream<Integer> boxed = intStream.boxed();
Integer reduceSum = boxed.reduce(0, Integer::sum);
System.out.println(reduceSum); //4200
}
}
```
```java
// 收集器对流的消耗
public class Stream {
public static void main(String[] args) {
//得到的是 Stream<Integer>
java.util.stream.Stream<Integer> integerStream = Data.menu.stream().map(Data.Dish::getCalories);
Integer reduce = integerStream.reduce(0, Integer::sum);
System.out.println(reduce); //4200
//得到的是 IntStream
IntStream intStream = Data.menu.stream().mapToInt(Data.Dish::getCalories);
int sum = intStream.sum();
// 下面这行报错:IllegalStateException: stream has already been operated upon or closed
// 因为sum() 是一个终止流方法,会消耗掉流,所以调用 intStream.boxed() 方法时候会报错
java.util.stream.Stream<Integer> boxed = intStream.boxed();
Integer reduceSum = boxed.reduce(0, Integer::sum);
System.out.println(sum); //4200
System.out.println(reduceSum); //4200
}
```
#### 3.构建流
**1.由值创建流**
```java
public class StreamCreate {
public static void main(String[] args) {
// 由值创建流
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
// 创建空流
Stream<Object> empty = Stream.empty();
}
}
```
**2.由数组创建流**
```java
public class StreamCreate {
public static void main(String[] args) {
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
System.out.println(sum); //41
}
}
```
**3.由文件创建流**
```java
public class StreamCreate {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) {
Set<String> collect = lines.flatMap(line -> Arrays.stream(line.split("")))
.distinct()
.collect(Collectors.toSet());
collect.forEach(System.out::print);
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
**4.由函数生成流**
Stream API提供了两个静态方法来从函数生成流 **Stream.iterate**和**Stream.generate**。这两个操作可以创建所谓的无限流不像从固定集合创建的流那样有固定大小的流。由iterate和generate产生的流会用给定的函数按需创建值因此可以无穷无尽地计算下去一般来说应该使用limit(n)来对这种流加以限制,以避免打印无穷多个值。
- **iterate**方法接受一个初始值在这里是0还有一个依次应用在每个产生的新值上的LambdaUnaryOperator\<T>类型)。
- **generate**方法也可让你按需生成一个无限流。但generate不是依次对每个新生成的值应用函数的。它接受一个Supplier\<T>类型的Lambda提供新的值。
```java
public class StreamCreate {
public static void main(String[] args) {
// 迭代
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
// 生成
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
}
}
```
### 第5章 使用流
你可以把Java 8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作中间操作和终端操作。中间操作可以链接起来**将一个流转换为另一个流**。这些操作不会消耗流,其目的是建立一个流水线。与此相反,**终端操作会消耗流**,以产生一个最终结果,例如返回流中的最大元素。
#### 1.中间操作和基本操作
**表5-1 中间操作和终端操作**
| 操作 | 类型 | 返回类型 | 使用的类型/函数式接口 | 函数描述符 |
| --------- | ----------------- | ------------ | ---------------------- | --------------- |
| filter | 中间 | Stream<T> | Predicate\<T> | T -> boolean |
| distinct | 中间(有状态-无界) | Stream<T> | | |
| skin | 中间(有状态-有界) | Stream<T> | long | |
| limit | 中间(有状态-有界) | Stream<T> | long | |
| map | 中间 | Stream<T> | Function<T,R> | T -> R |
| flatMap | 中间 | Stream<T> | Function<T,Stream\<R>> | T -> Stream\<R> |
| sorted | 中间(有状态-无界) | Stream<T> | Comparator\<T> | (T , T) -> int |
| anyMatch | 终端 | boolean | Predicate\<T> | T -> boolean |
| noneMatch | 终端 | boolean | Predicate\<T> | T -> boolean |
| allMatch | 终端 | boolean | Predicate\<T> | T -> boolean |
| findAny | 终端 | Optional\<T> | | |
| findFirst | 终端 | Optional\<T> | | |
| forEach | 终端 | void | Cosumer\<T> | T -> void |
| collect | 终端 | R | collector<T, A, R> | |
| reduce | 终端 | Optional\<T> | BinaryOperator\<T> | (T , T) -> T |
| count | 终端 | long | | |
#### 2.flatMap的使用
给 定 单 词 列 表["Hello","World"],你想要返回列表["H","e","l", "o","W","r","d"]。
**Arrays.stream()的方法可以接受一个数组并产生一个流 。**
```java
public class Stream {
public static void main(String[] args) {
String[] strings = {"Hello", "World"};
// 如下图 5.5
List<String[]> list01 = Arrays.stream(strings)
.map(s -> s.split(""))
.distinct().collect(Collectors.toList());
// 使用flatMap方法的效果是各个数组并不是分别映射成一个流而是映射成流的内容。 如下图5.6
List<String> list02 = Arrays.stream(strings)
.map(s -> s.split(""))
.flatMap(Arrays::stream)
.distinct().collect(Collectors.toList());
//每个单词转换成一个字母数组,然后把每个数组变成了一个独立的流。
List<java.util.stream.Stream<String>> list03 = Arrays.stream(strings)
.map(s -> s.split(""))
.map(Arrays::stream)
.distinct().collect(Collectors.toList());
list01.forEach(System.out::println);
list02.forEach(System.out::println);
list03.forEach(System.out::println);
}
}
```
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/flatmap1.png"/> </div></br>
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/flatmap2.png"/> </div></br>
#### 3.归约
```java
public class Stream {
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer reduce = integers.stream().reduce(0, (a, b) -> a + b);
System.out.println(reduce);
}
}
```
### 第6章 用流收集数据
#### 1.预定义收集器
预定义收集器主要指 Collectors类提供的工厂方法例如groupingBy创建的收集器。它们主要提供了三大功能
- 将流元素归约和汇总为一个值
- 元素分组
- 元素分区
**表6.1 Collectors 类的静态工厂方法**
| 工厂方法 | 返回类型 | 用于 |
| ----------------- | --------------------- | ------------------------------------------------------------ |
| toList | List\<T> | 把流中所有项目收集到一个List |
| toSet | Set\<T> | 把流中所有项目收集到一个Set,删除重复项 |
| toCollection | Collection\<T> | 把流中所有项目收集到给定的供应源创建的集合 |
| counting | Long | 计算流中元素的个数 |
| summingInt | Integer | 对流中项目的一个整数属性求和 |
| averagingInt | Double | 计算流中项目Integer属性的平均值 |
| summarizingInt | IntSummaryStatistics | 收集关于流中项目Integer属性的统计值例如最大、最小、总和与平均值 |
| joining | String | 连接对流中每个项目调用toString方法所生成的字符串 |
| maxBy | Optional\<T> | 查找最大元素的Optional,或如果流为空则为Optional.empty() |
| minBy | Optional\<T> | 查找最小元素的Optional,或如果流为空则为Optional.empty() |
| reducing | 规约操作产生的类型 | 从一个作为累加器的初始值开启利用BinaryOperator与流中的元素逐个结合从而将流归约为单个值 |
| collectingAndThen | 转换返回返回的类型 | 包裹另一个收集器,对其结果应用转换函数 |
| groupingBy | Map<K,List\<T>> | 根据项目的一个属性的值对流中项目作分组并将其属性值作为结果Map的键 |
| partitionBy | Map<Boolean,List\<T>> | 根据对流中每个项目应用谓词的结果来对项目进行区分 |
```java
import java.util.*;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.*;
public class Stream {
public static void main(String[] args) {
// toList
List<Data.Dish> dishList = Data.menu.stream().collect(toList());
// toSet
Set<Data.Dish> dishSet = Data.menu.stream().collect(Collectors.toSet());
// toCollection
ArrayList<Data.Dish> arrayList = Data.menu.stream()
.collect(Collectors.toCollection(ArrayList::new));
// counting
long count = Data.menu.stream().count();
// summingInt 可以用中间操作等价
Integer sum01 = Data.menu.stream()
.collect(Collectors.summingInt(Data.Dish::getCalories));
Integer sum02 = Data.menu.stream()
.mapToInt(Data.Dish::getCalories).sum();
// averagingInt
Double average = Data.menu.stream()
.collect(Collectors.averagingInt(Data.Dish::getCalories));
// summarizingInt
IntSummaryStatistics statistics = Data.menu.stream()
.collect(Collectors.summarizingInt(Data.Dish::getCalories));
statistics.getAverage();
statistics.getMax();
// joining
String joining = Data.menu.stream().map(Data.Dish::getName)
.collect(Collectors.joining(","));
// maxBy
Optional<Data.Dish> max = Data.menu.stream()
.max(Comparator.comparingInt(Data.Dish::getCalories));
// minBy
Optional<Data.Dish> min = Data.menu.stream()
.min(Comparator.comparingInt(Data.Dish::getCalories));
// reducing
Integer reduce01 = Data.menu.stream().map(Data.Dish::getCalories)
.reduce(0, Integer::sum);
Integer reduce02 = Data.menu.stream().map(Data.Dish::getCalories)
.reduce(0, Integer::sum);
// collectingAndThen
Integer size = Data.menu.stream().collect(collectingAndThen(toList(), List::size));
// groupingBy
Map<Data.Type, List<Data.Dish>> typeListMap = Data.menu.stream()
.collect(groupingBy(Data.Dish::getType));
// partitionBy
Map<Boolean, List<Data.Dish>> booleanListMap = Data.menu.stream()
.collect(partitioningBy(Data.Dish::isVegetarian));
}
}
```
## 第三部分 高效的Java 8编程
### 第12章 新的日期和时间API
#### 12.1 LocalDate、LocalTime、Instant、Duration、period
##### 1.使用 LocalDate 和 LocalTime
```java
public class NewDateApi {
public static void main(String[] args) {
// 创建日期
LocalDate date = LocalDate.of(2018, 10, 8);
int year = date.getYear(); // 2018
Month month = date.getMonth(); // OCTOBER
int value = month.getValue(); // 10
int dayOfMonth = date.getDayOfMonth(); // 8
int i = date.lengthOfMonth(); // 31
// 获取当前日期
LocalDate now = LocalDate.now();
//创建时间
LocalTime time = LocalTime.of(12, 13, 32);
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();
// 通过解析创建日期和时间
// the text to parse such as "2007-12-03", not null
LocalDate localDate = LocalDate.parse("2019-03-12");
// the text to parse such as "10:15:30", not null
LocalTime localTime = LocalTime.parse("12:21:45");
}
}
```
##### 2.使用LocalDateTime
```java
public class NewDateApi {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
LocalTime time = LocalTime.of(13, 45, 20);
LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
LocalDateTime dt2 = LocalDateTime.of(date, time);
LocalDateTime dt3 = date.atTime(13, 45, 20);
LocalDateTime dt4 = date.atTime(time);
LocalDateTime dt5 = time.atDate(date);
LocalDate localDate = dt1.toLocalDate();
LocalTime localTime = dt1.toLocalTime();
boolean equal = dt1.isEqual(dt2); // true
boolean equals = date.equals(localDate); // true
}
}
```
##### 3.时间间隔 Duration 或 Period
```java
// 计算时间间隔
public class NewDateApi {
public static void main(String[] args) {
LocalDate date01 = LocalDate.of(2014, Month.MARCH, 18);
LocalDate date02 = LocalDate.of(2012, Month.MARCH, 23);
LocalTime time01 = LocalTime.of(13, 45, 20);
LocalTime time02 = LocalTime.of(13, 12, 35);
// 计算日期间隔
Period between01 = Period.between(date01, date02);
// 计算时间间隔
Duration between02 = Duration.between(time01, time02);
// 间隔时间可能为正值 也可能为负值 可以用 isNegative 判断
System.out.println(between01.getDays());
System.out.println(between01.getYears());
System.out.println(between02.getSeconds());
}
}
```
```java
// 创建时间间隔
public class NewDateApi {
public static void main(String[] args) {
// 创建 Duration 和 Period 对象
Duration duration = Duration.ofMinutes(3);
Duration duration1 = Duration.of(3, ChronoUnit.MINUTES);
Period tenDays = Period.ofDays(10);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
}
}
```
#### 12.2 操纵、解析和格式化日期
##### 1.操纵日期加减
```java
public class NewDateApi {
public static void main(String[] args) {
// 以直接修改方式操作 LocalDate
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.withYear(2011);
LocalDate date3 = date2.withDayOfMonth(25);
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9);
// 以相对的方式操作 LocalDate
LocalDate date5 = date1.plusWeeks(1);
LocalDate date6 = date1.minusYears(3);
LocalDate date7 = date1.plus(6, ChronoUnit.MONTHS);
// 操作 LocalDate
LocalTime time = LocalTime.of(12, 3, 18);
LocalTime time1 = time.withHour(3);
LocalTime time2 = time.plus(3, ChronoUnit.HOURS);
System.out.println(time2.getHour());
}
}
```
##### 2.使用TemporalAdjusters
```java
import java.time.*;
import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;
import static java.time.temporal.TemporalAdjusters.nextOrSame;
public class NewDateApi {
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
LocalDate date3 = date2.with(lastDayOfMonth());
}
}
```
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/TemporalAdjuster类中的工厂方法.png"/> </div></br>
##### 3.日期格式解析
```java
public class NewDateApi {
public static void main(String[] args) {
// 使用内置格式解析
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); //2014-03-18
// 使用自定义格式解析
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);
}
}
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,254 +0,0 @@
# 《深入理解Java虚拟机》读书笔记
## 目录<br/>
<a href="#第二章-java内存区域与内存溢出异常">第二章 java内存区域与内存溢出异常</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#22-运行时数据区域">2.2 运行时数据区域</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#221--程序计数器">2.2.1 程序计数器</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#222--Java虚拟机栈">2.2.2 Java虚拟机栈</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#223-本地方法栈">2.2.3 本地方法栈</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#224-Java堆">2.2.4 Java堆</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#225-方法区">2.2.5 方法区</a><br/>
<a href="#第四章-虚拟机性能监控与故障处理工具">第四章 虚拟机性能监控与故障处理工具</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#421-JDK命令行工具">4.2.1 JDK命令行工具</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#421-jps虚拟机进程状况工具">4.2.1 jps虚拟机进程状况工具 </a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#422-jstat虚拟机统计信息监视工具">4.2.2 jstat虚拟机统计信息监视工具</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1-gc-参数返回结果">1. gc 参数返回结果</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2-class-参数返回结果">2. class 参数返回结果</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#3-gcmetacapacity-参数返回结果">3. gcmetacapacity 参数返回结果</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#423-jinfoJava配置信息工具">4.2.3 jinfoJava配置信息工具</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#424-jmapJava内存映像工具">4.2.4 jmapJava内存映像工具 </a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#425-jhat虚拟机堆转储快照分析工具">4.2.5 jhat虚拟机堆转储快照分析工具 </a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#426-jstackJava堆栈跟踪工具">4.2.6 jstackJava堆栈跟踪工具 </a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#43-JDK的可视化工具">4.3 JDK的可视化工具 </a><br/>
<a href="#第十二章-Java内存模型">第十二章 Java内存模型</a><br/>
## 正文<br/>
## 第二章 java内存区域与内存溢出异常
### 2.2 运行时数据区域
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/java虚拟机运行时数据区.png"/> </div></br>
#### 2.2.1 程序计数器
**当前线程所执行的字节码的行号指示器。**
- 为了线程切换后能够恢复到正确地执行位置,每个线程都需要有一个独立的程序计数器;
- 如果正在执行java方法计数器记录的是正在执行的虚拟机字节码指令的地址如果执行的是Native方法则计数器值为空
- 此内存区域是唯一一个在java虚拟机规范中没有规定任何outOfMemoryError情况的区域。
#### 2.2.2 Java虚拟机栈
虚拟机栈描述的是Java方法执行的内存模型每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出入口等信息。每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机中入栈到出栈的过程。
- 局部变量表存放了编译器可知的各种基本数据类型、对象引用和returnAddress类型指向一条字节码指令的地址
- 在java虚拟机规范中对这个区域规定了两种异常
- 如果线程请求的栈深入大于虚拟机所允许的深度将抛出StackOverflowError异常
- 如果虚拟机栈扩展时无法申请到足够的内存就会抛出OutOfMemoryError异常。
#### 2.2.3 本地方法栈
与虚拟机栈类似针对Native 方法服务。
#### 2.2.4 Java堆
此内存区域的唯一目的就是存放对象实例几乎所有的对象实例都在这里分配内存。Java 堆可以处于物理上不连续的内存空间中只要是逻辑上是连续的即可。如果堆中没有内存完成实例分配并且堆也无法在扩展时将会抛出OutOfMemoryError异常。
#### 2.2.5 方法区
方法区与Java堆一样是各个线程共享的内存区域它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
- 当方法区无法满足内存分配的需求时将会抛出OutOfMemoryError异常。
- **运行时常量池**是方法区的一部分Class文件中出了有类的版本、字段、方法、接口等描述信息外还有一项信息是常量池用于存放编译期生成的各种字面量和符号引用这部分内容将在类加载后进入方法区的运行时常量池中存在。
## 第四章 虚拟机性能监控与故障处理工具
部分内容参考自博客:[JDK的命令行工具](https://blog.csdn.net/qq_31156277/article/details/80035236)
### 4.2.1 JDK命令行工具
#### 4.2.1 jps虚拟机进程状况工具
命令格式: jps \[options] [hostid]
| 参数 | 描述 |
| ---- | ------------------------------------------------ |
| -l | 输出主类的全名如果是执行的jar则输出jar的路径 |
| -v | 输出JVM启动时的JVM参数 |
| -m | 输出虚拟机进程启动时传递给主类main() 函数的参数 |
#### 4.2.2 jstat虚拟机统计信息监视工具
命令格式jstat [options] vmid [interval \[s|ms][count]] ]
命令格式jstat \[-命令选项]\[vmid]\[间隔时间/毫秒][查询次数]
| 参数 | 功能作用 |
| ----------------- | ------------------------------------------------------------ |
| -class | 监视类装载、卸载数量,以及总空间和装载耗时等 |
| -gc | 监视堆中 eden、 survivor 、老年代、元空间等空间大小和已使用情况GC次数、耗时等 |
| -gcmetacapacity | 元空间 |
| -gcutil | 与gc 类似,但是注重的是占比情况 |
| -printcompilation | 输出已经被JIT重新编译的方法 |
| -gcoldcapacity | 老年代统计信息 |
| -gcnew | 新生代 |
| -gccause | 与-gcutil相似但是会输出上一次GC的原因 |
##### 1. gc 参数返回结果
使用-gc 命令; 为了能够更加直观在程序中设置了VM相关参数 然后运行、查看结果并分析。
| 参数 | 解析 |
| ---- | -------------------- |
| S0C | surivor(s0)区域大小 |
| s1c | s1区大小 |
| S0U | S0的使用大小 |
| S1U | S1的使用大小 |
| EC | eden可以使用的大小 |
| EU | eden已经使用 |
| OC | 老年代可以使用的大小 |
| OU | 老年代已经使用的带下 |
| MC | 元空间可以使用的大小 |
| MU | 元空间已经使用的大小 |
| CCSC | 压缩类空间大小 |
| CCSU | 压缩类已经使用大小 |
| YGC | 年轻代垃圾回收次数 |
| YGCT | 年轻代垃圾回收总耗时 |
| FGC | 老年代垃圾回收次数 |
| FGCT | 老年代垃圾回收总耗时 |
| GCT | 垃圾回收消耗总时间 |
##### 2. class 参数返回结果
-class 参数; 监视类装载、卸载数量、总空间以及装载所耗费的时间。
| 参数 | 解析 |
| -------- | --------------- |
| Loaded | 加载class的数量 |
| Bytes | 占用空间大小 |
| Unloaded | 未加载数量 |
| Bytes | 未加载占用空间 |
| Time | 时间 |
##### 3. gcmetacapacity 参数返回结果
元数据空间统计(-gcmetacapacity)
| 参数 | 描述 |
| ----- | ---------------------- |
| MCMN | 最小元数据容量 |
| MCMX | 最大元数据容量 |
| MC | 当前元数据空间大小 |
| CCSMN | 最小压缩类空间大小 |
| CCSMX | 最大压缩类空间大小 |
| CCSC | 当前压缩类空间大小 |
| YGC | 年轻代垃圾回收次数 |
| FGC | 老年代垃圾回收次数 |
| FGCT | 老年代垃圾回收消耗时间 |
| GCT | 垃圾回收消耗总时间 |
#### 4.2.3 jinfoJava配置信息工具
命令格式jinfo [option] ipd
在控制台输入 jinfo ,则会提示相关命令参数,可借助提示执行相关命令。
```shell
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
<no option> to print both of the above
```
#### 4.2.4 jmapJava内存映像工具
`jmap`JVM Memory Map for java命令用于生成`堆转储快照`; 当然还可以使用`-XX:HeapDumpOnOutOfMemoryError` 参数可以让虚拟机在OOM异常之后自动生产dump文件。
| 选项 | 作用 |
| ------------- | ------------------------------------------------------------ |
| -dump | 生成Java堆转储快照。 格式 -dump:[live,]format=b,file=< filename >,其中live子参数说明是否只dump出存活的对象 |
| finalizerinfo | 显示F-Queue中等待Finalizer线程执行finalize方法的对象 |
| -heap | 显示java堆详细信息如使用哪种收集器、参数配置、分代状况等 |
| -histo | 显示堆中对象统计信息,包括类,实例数量、合计容量 |
| -F | 当虚拟机进程对 -dump选项没有响应时可使用这个选项强制生成dump快照 |
#### 4.2.5 jhat虚拟机堆转储快照分析工具
可用 VisualVM 或者其他可视化分析工具代替
#### 4.2.6 jstackJava堆栈跟踪工具
jstack [ option ] vmid
| 参数 | 作用 |
| ---- | -------------------------------------------- |
| -F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
| -l | 除堆栈外,显示关于锁的附加信息 |
| -m | 如果调用本地方法的话,可以显示 c/C++的堆栈 |
### 4.3 JDK的可视化工具
官方工具1 JConsoleJava监视与管理控制台
官方工具2 VisualVM多合一故障处理工具
IDEA下推荐插件JProfiler
## 第十二章 Java内存模型
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/java内存模型.png"/> </div></br>
关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、 如何从工作内存同步回主内存之类的实现细节Java内存模型中定义了以下8种操作来完成
1. **lock锁定**:作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
2. **unlock解锁**:作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
3. **read读取**作用于主内存的变量它把一个变量的值从主内存传输到线程的工作内存中以便随后的load动作使用。
4. **load载入**作用于工作内存的变量它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
5. **use使用**:作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
6. **assign赋值**:作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
7. **store存储**作用于工作内存的变量它把工作内存中一个变量的值传送到主内存中以便随后的write操作使用。
8. **write写入**作用于主内存的变量它把store操作从工作内存中得到的变量的值放入主内存的变量中。
**Java内存模型还规定了在执行上述8种基本操作时必须满足如下规则**
1. 不允许read和load、 store和write操作之一单独出现即不允许一个变量从主内存读取了但工作内存不接受或者从工作内存发起回写了但主内存不接受的情况出现。
2. 不允许一个线程丢弃它的最近的assign操作即变量在工作内存中改变了之后必须把该变化同步回主内存。
3. 不允许一个线程无原因地没有发生过任何assign操作把数据从线程的工作内存同步回主内存中。
4. 一个新的变量只能在主内存中“诞生”不允许在工作内存中直接使用一个未被初始化load或assign的变量换句话说就是对一个变量实施use、 store操作之前必须先执行过了assign和load操作。
5. 一个变量在同一个时刻只允许一条线程对其进行lock操作但lock操作可以被同一条线程重复执行多次多次执行lock后只有执行相同次数的unlock操作变量才会被解锁。
6. 如果对一个变量执行lock操作那将会清空工作内存中此变量的值在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值。
7. 如果一个变量事先没有被lock操作锁定那就不允许对它执行unlock操作也不允许去unlock一个被其他线程锁定住的变量。
8. 对一个变量执行unlock操作之前必须先把此变量同步回主内存中执行store、 write操作
**先行发生原则:**
1. **程序次序规则**Program Order Rule在一个线程内按照程序代码顺序书写在前面的操作先行发生于书写在后面的操作。 准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、 循环等结构。
2. **管程锁定规则**Monitor Lock Rule一个unlock操作先行发生于后面对同一个锁的lock操作。 这里必须强调的是同一个锁,而“后面”是指时间上的先后顺序。
3. **volatile变量规则**Volatile Variable Rule对一个volatile变量的写操作先行发生于后面对这个变量的读操作这里的“后面”同样是指时间上的先后顺序。
4. **线程启动规则**Thread Start RuleThread对象的start方法先行发生于此线程的每一个动作。
5. **线程终止规则**Thread Termination Rule线程中的所有操作都先行发生于对此线程的终止检测我们可以通过Thread.join方法结束、 Thread.isAlive的返回值等手段检测到线程已经终止执行。
6. **线程中断规则**Thread Interruption Rule对线程interrupt方法的调用先行发生于被中断线程的代码检测到中断事件的发生可以通过Thread.interrupted方法检测到是否有中断发生。
7. **对象终结规则**Finalizer Rule一个对象的初始化完成构造函数执行结束先行发生于它的finalize方法的开始。
8. **传递性**Transitivity如果操作A先行发生于操作B操作B先行发生于操作C那就可以得出操作A先行发生于操作C的结论。