0%

Java高效编程总结

[TOC]

1 函数式编程

2 流式编程

3 资源关闭

3.1 垃圾回收(GC)的特点

  • 垃圾回收机制只负责回收堆内存资源,不会回收任何物理资源

  • 程序无法精确控制垃圾回收动作的具体发生时间

  • 在垃圾回收之前,总会先调用它的finalize方法

3.2 常见需手动释放的物理资源

  • 文件/流资源

  • 套接字资源

  • 数据库连接资源

3.3 物理资源可以不手动释放吗?

  • 资源被长时间无效占用

  • 超过最大限制后,将无资源可用

  • 导致系统无法正常运行

3.4 传统方式关闭流资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* JDK7之前的文件拷贝功能
*/
public class FileCopyTest {

@Test
public void copyFile() {
/**
* 1. 创建输入/输出流
* 2. 执行文件拷贝,读取文件内容,写入到另一个文件中
* 3. **关闭文件流资源**
*/

// 定义输入路径和输出路径
String originalUrl = "lib/FileCopyTest.java";
String targetUrl = "targetTest/target.txt";

// 声明文件输入流,文件输出流
FileInputStream originalFileInputStream = null;
FileOutputStream targetFileOutputStream = null;

try {
// 实例化文件流对象
originalFileInputStream =
new FileInputStream(originalUrl);

targetFileOutputStream =
new FileOutputStream(targetUrl);

// 读取的字节信息
int content;

// 迭代,读取/写入字节
while ((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {

// 关闭流资源
if (targetFileOutputStream != null) {
try {
targetFileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (originalFileInputStream != null) {
try {
originalFileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}

}

3.5 TWR方式关闭流资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class NewFileCopyTest {

@Test
public void copyFile() {

// 先定义输入/输出路径
String originalUrl = "lib/NewFileCopyTest.java";
String targetUrl = "targetTest/new.txt";

// 初始化输入/输出流对象
try (
FileInputStream originalFileInputStream =
new FileInputStream(originalUrl);

FileOutputStream targetFileOutputStream =
new FileOutputStream(targetUrl);
) {

int content;

// 迭代,拷贝数据
while ((content = originalFileInputStream.read()) != -1) {
targetFileOutputStream.write(content);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}

}

3.6 TWR简介

try-with-resource

  • Java7引入新特性

  • 优雅关闭资源

  • 一种java语法糖

3.7 TWR使用

  • 多资源自动关闭

  • 实现AutoCloseable接口

  • 避免异常屏蔽

3.8 资源关闭顺序问题

  • 先开后关原则

  • 从外到内原则

  • 底层资源原则声明

3.9 资源关闭特殊情况

  • 资源对象被return的情况,由调用方关闭

  • ByteArrayInputStream等不需要检查关闭的资源对象

  • 使用Socket获取InputStream和OutputStream对象不需要关闭

4 工具集

4.1 Guava简介

背靠Google好乘凉,Guava工程包含了若干被Google的Java项目广泛依赖的核心库,例如:集合,缓存,原生类型支持,并发库,通用注解,字符串处理,I/O等等。

所有这些工具每天都在被Google的工程师应用在产品中。

4.2 使用和避免null

大多数情况下,使用null表明的是某种缺失情况。

Guava引入Optional<T>表明可能为null的T类型引用。Optional实例可能包含非null的引用(引用存在),也可能什么也不包括(引用缺失)。

正是受到Guava的启发,Java8将Optional类作为一个新特性引入到Java8的类库。

4.3 实战案例:Java8新特性Optional

4.4 不可变集合

创建对象的不可变拷贝是一项很好的防御性编程技巧

Guava为所有的JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。

不可变对象的优点

img

4.5 新集合类型

4.6 实战:新集合类型使用

4.7 集合工具类

4.8 实战:IO流工具类的使用

4.9 总结

5 线程池

6 实用工具

6.1 Lombok简介

Project Lombok是一个Java库,可以自动插入编辑器并构建工具,为Java增添色彩。永远不要再写另一个getter或equals方法,使用一个注释,您的类具有一个功能齐全的构建器,自动化您的日志记录变量。

​ –Lombok官网

6.2 Lombok实现原理

注解的两种解析方式

  • 运行时解析—类似于反射
  • 编译时解析—Lombok

编译时解析的两种机制

  • Annotation Processing Tool(注解处理器)—-JDK1.8去除
  • Pluggable Annotation Processing API(JSR269插入式注解处理器)

image

6.3 Lombok插件安装

IDEA–>setting–>plugins–>搜索lombok安装即可

6.4 Lombok常用注解使用

实战:演示Lombok注解使用方式,并通过查看编译后class文件,理解其工作原理

https://www.cnblogs.com/ooo0/p/12448096.html

https://www.cnblogs.com/muxi0407/p/11611885.html

image

1.@Data注解

一种大而全的注解:包含@Getter,@Setter,@ToString,@EqualsAndHashCode,@NoArgsConstructor

2.@Val注解

弱语言变量,作用范围是本地方法

https://blog.csdn.net/cauchy6317/article/details/102851120

3.@NotNull注解:生成非空的检查

4.@Builder注解:简化对象创建过程

5.@Singular注解:配合@Builder注解,简化集合类型操作

6.5 Lombok优缺点

lombok虽然可以极大的提高我们的开发效率,但却降低了源代码的可读性和完整性,也加大了对问题排查的难度

7 验证框架

7.1 分层验证与JavaBean验证

分层验证模型

image-20210506214821951

JavaBean验证

image-20210506214839961

Bean Validation简介

Bean Validation为JavaBean验证定义了相应的元数据模型和API

JCP,JSR简介

JCP(Java Community Process)成立于1998年,是使有兴趣的各方参与定义Java的特性和未来版本的正式过程

JCP使用JSR(Java规范请求,Java Specification Requests)作为正式规范文档,描述被提议加入到Java体系中的规范和技术。

JSR303,Bean Validation 1.0

JSR349,Bean Validation 1.1

JSR380,Bean Validation 2.0

Bean Validation与Hibernate Validator

Bean Validation 1.0参考实现:Hibernate Validator 4.3.1.Final

Bean Validation 1.1参考实现:Hibernate Validator 5.1.1.Final

Bean Validation 2.0参考实现:Hibernate Validator 6.0.1.Final

常用约束注解

  • 空值校验类:@Null,@NotNull,@NotEmpty,@NotBlank等
  • 范围校验类:@Min,@Size,@Digits,@Future,@Negative等
  • 其他校验类:@Email,@URL,@AssertTrue,@Pattern等

@NotBlank 用于 String 判断空格
@NotEmpty 用于集合
@NotNull 用在基本类型上

注解 描述
@AssertFalse 被注释的元素必须为 false
@AssertTrue 同@AssertFalse
@DecimalMax 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin 同DecimalMax
@Digits 被注释的元素是数字
@Future 将来的日期
@Max 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Min 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@NotNull 不能是Null
@Null 元素是Null
@Past 被注释的元素必须是一个过去的日期
@Pattern 被注释的元素必须符合指定的正则表达式
@Szie 被注释的元素必须在指定长度内
@Email 元素必须是格式良好的电子邮箱地址
@Length 字符串的大小必须在指定的范围内,有min和max参数
@NotEmpty 字符串的不能是空
@NotBlank 字符串不能使空,但是与@NotEmpty不同的是尾随的空白被忽略
@URL 字符串必须是一个URL

8-5 案例演示框架搭建 (05:13)

引入pom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- Validation 相关依赖 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.16.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>

简单的使用,还是以Person实体类为例(大家在尝试时最好在web项目上,毕竟这个功能基本也都在web上才用得到。非web项目可能会出现一些错误,这时候就要引入el依赖):

1
2
3
4
5
6
7
8
9
10
11
@Data
@AllArgsConstructor
public class Person {
@NotNull(message = "用户名不能为空")
@Size(min = 2,max = 15)
private String name;
@NotNull
private int age;
@NotNull(message = "性别不能为空")
private String gender;
}
1
2
3
4
5
6
private static Validator validator=Validation.buildDefaultValidatorFactory().getValidator();//初始化验证器
public static void main(String[] args) {
Person person=new Person("",15,"男");//新建一个数据
Set<ConstraintViolation<Person>> validate = validator.validate(person);//进行验证
validate.forEach(item ->System.out.println(item.getMessage()));//对验证结果进行输出,就是输出注解后面的message。
}

7.2 完成验证的步骤

  • 约束注解的定义
  • 约束验证规则(结束验证器)
  • 约束注解的声明
  • 约束验证流程

7.3 测试案例

自定义手机号约束注解

  • 定义@interface Phone注解
  • 实现约束验证器PhoneValidator.java
  • 声明@Phone约束验证
  • 执行手机号约束验证流程

8 常用工具

开发常用工具总结:https://liuurick.github.io/2021/04/18/%E5%BC%80%E5%8F%91%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7%E6%80%BB%E7%BB%93/

开发工具

自测工具

检查工具

9 综合实战

整合一下,搭建通用型基础组件

  • 集成MyBatis-plus实现数据持久化
  • 集成CaffeineCache(GuavaCache替代品)实现本地缓存
  • 集成Lombok注解
  • 集成校验框架实现自动/手动数据校验
  • 实现统一异常处理
  • 集成Guava令牌桶实现全局限流器
  • 使用线程池实现任务异步处理
  • 使用TWR实现文件关闭
  • 集成EasyExcel实现Excel异步导出
  • 实现VO/DTO/DO实现代码分层
  • 使用Stream实现集合操作
  • 集成Swagger2实现接口文档自动生成
  • 使用TraceId实现系统请求追踪

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<dependencies>

<!-- Swagger2支持 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>

<!-- EasyExcel相关支持 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>5.2</version>
</dependency>

<!-- Guava支持 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Caffeine Cache支持 -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>

<!-- Mybatis Plus集成 -->
<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis支持 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- mybatis plus支持 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

集成Mybatis Plus步骤

  1. 在pom.xml文件引入相关的jar包依赖
  2. 实现XxxMapper接口。通过此接口来操作数据持久化
  3. 对XxxDO实体进行注解的定义,如:数据库表名,字段的定义
  4. 如需修改Plus默认配置,需实现MybatisPlusConfig类
  5. 如需要自定义一个方法,需实现XxxMapper.xml,来定义自定义SQL

实现VO/DTO/DO实现代码分层

领域模型转换那些事儿:http://www.imooc.com/article/293314

图片描述

自动更新系统级字段

  1. 公共元数据处理器
  2. 为XxxDO配置注解

集成验证框架步骤

  1. 在pom.xml引入相关的jar包支持
  2. 在待验证的实体里面添加相应的注解
  3. 在Controller中添加相应的注解
  4. 做参数校验工具类,完成service层的参数校验

实现统一异常处理功能

  1. 实现一个异常处理的类,并且用@ControllerAdvice修饰

集成CaffeineCache缓存功能

  1. @Cacheable : 缓存数据,一般用在查询方法上。将查询到的数据进行缓存 @CachePut : 更新方法上,将数据从缓存中进行更新 @CacheEvict : 删除缓存
  2. pom.xml cache相关的jar包支持
  3. CacheManager Bean
  4. 使用注解,标识我们的方法哪些需要缓存

集成Guava令牌桶实现全局限流功能

  1. 先pom.xml引入Guava工具包的支持
  2. 定义一个拦截器,实现令牌的发放和获取
  3. 将拦截器配置到web系统中

使用TraceId实现日志跟踪

  1. 建立一个过滤器,在过滤器中给线程设置TraceId
  2. 将日志配置文件进行修改,把TraceId打印到日志中

文件上传下载

  1. 文件上传的Controller,负责处理文件上传
  2. 文件上传的服务接口,通过接口的形式来定义出文件上传的功能
  3. 实现文件上传业务逻辑
  4. 文件下载,采用静态路径映射的方式实现

数据导出功能

  1. pom.xml把相关的jar配置好
  2. UserController新增加数据导出的方法
  3. 要实现数据导出的功能
    • 定义导出实体
    • 分批加载数据,分批使用EasyExcel导出
    • 将导出的文件上传

导出功能异步化

  1. 先创建线程池
  2. 将导出方法使用@Aync注解标记为异步执行

使用Swagger2帮助我们生成API文档

  1. pom.xml引入jar包
  2. 配置Swagger2的配置类
  3. Controller及相关的实体中写对应的注解