零零散散
# jdk安装
mac m1 安装 :java jdk、支持动态切换jdk (opens new window)
MAC JDK 卸载方法(彻底卸载) (opens new window)
source ~/.bash_profile
切换
jdk21
source /etc/profile
java -version
2
3
4
5
6
# 常用工具方法
# guava工具
# 集合(Lists)
# 1.创建和添加对象
正常情况下,我们在java
中创建和使用List
的时候,基本都是这样的:
// 创建集合
List<String> stringList1 = new ArrayList<>();
// 添加对象
stringList1.add("hello");
stringList1.add("world");
2
3
4
5
但是,如果你用了guava
,那上面这些你都可以一步到位:
List<String> stringList2 = Lists.newArrayList("hello", "world");
还支持直接传入数组:
String[] strings = new String[] {"1231", "23432423"};
ArrayList<String> strings1 = Lists.newArrayList(strings);
2
# 2.list分割
更强大的是,它还支持List
分割,我们在日常开发中经常有这样的需求,比如某个接口或方法限制了List
数据量大小(比如list
的大小不能超过200
),这时候你如果自己手动写一个分割工具类就很麻烦,但如果用guava
,那就很简单:
List<List<String>> partition = Lists.partition(stringList1, 200);
上面代码的作用就是把我们的stringList1
分割成200
一份的小list
,这时候你再配合上forEach
,需求就完美实现了。
让你的开发过程更简单,更便捷,其他List
的子类创建类似。
# 3.list反转
实际开发中,经常要将list
反转,比如1, 2, 3, 4
的list
反转成4, 3, 2, 1
,自己写的话,需要写个for
循环,然后反向输出到另一个List
,但是用guava
就贼简单:
List<Integer> integerList = Lists.newArrayList(1, 2, 3, 4);
// 反转list
List<Integer> reverse = Lists.reverse(integerList);
2
3
# 4.list转换
比如我要将一个List<String>
根据一定的条件转换成一个List<Boolean>
,我可以这样操作:
List<String> stringList2 = Lists.newArrayList("hello", "world", "");
List<Boolean> transform = Lists.transform(stringList2, s -> !"".equals(s));
2
我转换的条件是只有不是空字符串就是true
,这里s -> !"".equals(s)
是lamubda
表达式的写法(最近一直在提这个,这个现在确实已经是主流了,展开写确实占行数:
List<Boolean> transform2 = Lists.transform(stringList2,
new Function<String, Boolean>() {
@Override
public @Nullable Boolean apply(@Nullable String input) {
return !"".equals(input);
}
});
2
3
4
5
6
7
# Maps
# 1.创建map
HashMap<Object, Object> objectObjectHashMap = Maps.newHashMap();
HashMap<Object, Object> objectObjectHashMap1 = Maps.newHashMap(objectObjectHashMap);
// 空map
Map<String, String> params = Maps.newHashMap();
2
3
4
# 2.比较两个map
这个方法就很强大,不仅可以返回两个map
的交集,还能返回每个map
不同的地方,结果都是map
这个方法就很强大,不仅可以返回两个map
的交集,还能返回每个map
不同的地方,结果都是map
HashMap<Object, Object> objectObjectHashMap = Maps.newHashMap();
objectObjectHashMap.put("k1", "v1");
objectObjectHashMap.put("k2", "v2");
objectObjectHashMap.put("k3", "v3");
HashMap<Object, Object> objectObjectHashMap1 = Maps.newHashMap(objectObjectHashMap);
objectObjectHashMap.put("k4", "v4");
objectObjectHashMap1.put("k5", "v5");
// 比较两个map
MapDifference<Object, Object> difference = Maps.difference(objectObjectHashMap, objectObjectHashMap1);
// 返回交集
Map<Object, Object> objectObjectMapCommon = difference.entriesInCommon();
// 返回左侧map特有的
Map<Object, Object> objectObjectMap1Left = difference.entriesOnlyOnLeft();
// 返回右侧map特有的
Map<Object, Object> objectObjectMap2Right = difference.entriesOnlyOnRight();
System.out.println(objectObjectMapCommon);
System.out.println(objectObjectMap1Left);
System.out.println(objectObjectMap2Right);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 3.将集合转为Map
这里还提供了将List
等集合转为map
的方法:
ImmutableMap<String, String> stringStringImmutableMap2 = Maps.toMap(stringList, s -> s);
上面的代码就是将一个list
转成key
和value
都一样的map
。
或者将map
转换为新的map
:
ImmutableMap<Map.Entry<String, Object>, Boolean> entryBooleanImmutableMap = Maps.toMap(stringObjectImmutableMap.entrySet(), k -> "123123".equals(k));
# 日志打印
log.error打印异常堆栈问题 (opens new window)
# @EnableAsync
SpringBoot利用@Async注解实现异步调用 (opens new window)
@EnableAsync的使用、进阶、源码分析 (opens new window)
SpringBoot注解@Async (opens new window)
注意:异步方法sync虽然加了@Async,但由于sync是在同个类里面,对于主方法mainFunc来说,调用子异步方法sync是通过当前对象去调用的,而不是通过代理对象,因而@Async不生效
注意:默认线程池配置 Spring Boot 使用 TaskExecutionAutoConfiguration 进行默认的 TaskExecutor 配置,默认使用的是 SimpleAsyncTaskExecutor,而 SimpleAsyncTaskExecutor 并不是一个真正的线程池,它会为每个任务创建一个新的线程。 如果你想使用 线程池 来管理异步任务,通常需要显式定义 ThreadPoolTaskExecutor,否则默认情况下会导致线程资源浪费。 如果没有指定 @Async("asyncExecutor"),Spring 仍会使用默认的 SimpleAsyncTaskExecutor,它不会复用线程,而是每次创建新线程,这在高并发下可能会导致性能问题。
我的机器是4核/6G AsyncConfig 的asyncExecutor 配置
- 核心线程数 (corePoolSize):通常设置为 CPU 核心数,即 4,这样可以保证 CPU 充分利用。
- 最大线程数 (maxPoolSize):一般是 核心数的 2~4 倍,可设为 8~12,根据具体任务并发量调整。
- 队列容量 (queueCapacity):设置为 100~200,如果任务很多,可以增大队列,避免任务直接创建新线程。
- 线程存活时间 (keepAliveSeconds):非核心线程的存活时间,设为 60 秒,避免资源浪费。
- 线程名前缀:设置统一前缀,方便日志排查。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4); // 4核CPU,对应核心线程数
executor.setMaxPoolSize(10); // 最大线程数,建议 2~3 倍于核心线程数
executor.setQueueCapacity(200); // 任务队列容量,防止过多任务导致线程频繁创建销毁
executor.setKeepAliveSeconds(60); // 非核心线程的存活时间
executor.setThreadNamePrefix("AsyncExecutor-"); // 线程名前缀
executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略,调用者执行任务,避免丢失
executor.initialize();
return executor;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# SpringBoot
Spring Boot框架知识总结(超详细,一次性到位) (opens new window)
搭建SpringBoot项目——开发环境搭建开发环境搭建 (opens new window)
SpringBoot配置文件:-Dspring.profiles.active的三种激活方式 (opens new window)
Springboot 整合Retry 实现重试机制 (opens new window)
SpringRetry重试机制 (opens new window)
HttpServletResponse详解 (opens new window)
IDEA2023版本创建Sping项目只能勾选17和21,却无法使用Java8?(已解决) (opens new window)
springboot @Slf4j+logback 配置详解 (opens new window)
# 远程调试
-Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9000
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9000
2
这两行是用来配置Java应用程序的调试参数,并启用Java远程调试功能。它们的写法略有不同,但实际上是等效的。
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9000
:- 这是一种旧的写法,使用了
-agentlib
参数来加载Java Debug Wire Protocol (JDWP) 的代理库。 jdwp
是用于启用JDWP的关键字。transport=dt_socket
指定了JDWP传输方式为基于Socket的传输。server=y
表示应用程序将作为调试服务器。suspend=n
表示不暂停应用程序的启动,即立即开始调试。address=9000
指定了调试服务器监听的端口号为9000。
- 这是一种旧的写法,使用了
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9000
:- 这是一种较新的写法,使用了
-Xrunjdwp
参数来启用JDWP。 transport=dt_socket
指定了JDWP传输方式为基于Socket的传输。server=y
表示应用程序将作为调试服务器。suspend=n
表示不暂停应用程序的启动,即立即开始调试。address=9000
指定了调试服务器监听的端口号为9000。
- 这是一种较新的写法,使用了
两种写法在功能上是等效的,都是用来启用Java应用程序的远程调试功能,并指定调试服务器的传输方式和监听端口号。只是在命令行参数的写法上稍有不同,但实际效果是一样的。开发人员可以根据自己的喜好选择其中一种写法来配置Java应用程序的调试参数。
# 状态机
Spring StateMachine 状态机的使用 (opens new window)
状态机的基本原理以及SSM实践 (opens new window)
Spring StateMachine官方文档 (opens new window)
springboot整合redis抛UnsatisfiedDependencyException异常 (opens new window)
Spring Statemachine应用实践 (opens new window)
# Mapstruct
Bean转换工具MapStruct看这一篇就够了 (opens new window)
# jVM参数
- OmitStackTraceInFastThrow
异常栈信息不见了之JVM参数OmitStackTraceInFastThrow (opens new window)
- 常用垃圾收集器参数
参数 | 描述 |
---|---|
UseSerialGC | 虚拟机在运行在 Client 模式下的默认值,打开此开关后,使用Serial+Serial Old 收集器组合进行内存回收 |
UseParNewGC | 使用 ParNew + Serial Old 收集器组合进行内存回收 |
UseConcMarkSweepGC | 使用 ParNew + CMS + Serial Old 的收集器组合尽心内存回收,当 CMS 出现Concurrent Mode Failure 失败后会使用 Serial Old 作为备用收集器 |
UseParallelOldGC | 使用 Parallel Scavenge + Parallel Old 的收集器组合 |
UseParallelGC | 使用 Parallel Scavenge + Serial Old (PS MarkSweep)的收集器组合 |
SurvivorRatio | 新生代中 Eden 和任何一个 Survivor 区域的容量比值,默认为 8 |
PretenureSizeThreshold | 直接晋升到老年代对象的大小,单位是Byte |
UseAdaptiveSizePolicy | 动态调整 Java 堆中各区域的大小以及进入老年代的年龄 |
ParallelGCThreads | 设置并行 GC 时进行内存回收的线程数 |
GCTimeRatio | GC 时间占总时间的比率,默认值为99,只在 Parallel Scavenge 收集器的时候生效 |
MaxGCPauseMillis | 设置 GC 最大的停顿时间,只在 Parallel Scavenge 收集器的时候生效 |
CMSInitiatingOccupancyFraction | 设置 CMS 收集器在老年代空间被使用多少后触发垃圾收集,默认是68%,仅在 CMS 收集器上生效 |
CMSFullGCsBeforeCompaction | 设置 CMS 收集器在进行多少次垃圾回收之后启动一次内存碎片整理 |
UseG1GC | 使用 G1 (Garbage First) 垃圾收集器 |
MaxGCPauseMillis | 设置最大GC停顿时间(GC pause time)指标(target). 这是一个软性指标(sox goal), JVM 会尽量去达成这个目标. |
G1HeapRegionSize | 使用G1时Java堆会被分为大小统一的的区(region)。此参数可以指定每个 heap区的大小. 默认值将根据 heap size 算出最优解. 最小值为 1Mb, 最大值为 32Mb. |
使用 G1 (Garbage First) 垃圾收集器 -XX:+UseG1GC -XX:+ParallelRefProcEnabled
G1垃圾回收参数调优及MySQL虚引用造成GC时间过长分析 | 京东云技术团队 (opens new window)
-XX:HeapDumpPath=/opt/service/logs/ -XX:+HeapDumpOnOutOfMemoryError
HeapDumpOnOutOfMemoryError、HeapDumpPath、ErrorFile 是每个 Java 应用都应该配置的参数。正常情况下,我们通过 jmap 获取应用程序的堆信息;异常情况下,比如发生了 OOM,通过这三个配置参数,即可在发生OOM的时候,自动 dump 一份堆信息到指定的目录中。
# IDEA插件
# Rebel激活
2023 Idea 热部署 JRebel 插件激活方法 (opens new window)
JrebelLicenseServerforJava (opens new window)
注意修改镜像为:
FROM openjdk:8-jre-alpine
# EasyExcel
EasyExcel 轻松读取Excel (opens new window)
EasyExcel 学习笔记 - 读Excel (opens new window)
使用easyexcel读excel(实现通用listener) (opens new window)
Spring Boot通过EasyExcel异步多线程实现大数据量Excel导入,百万数据30秒 (opens new window)
Spring Boot通过EasyExcel异步多线程实现大数据量Excel导入,百万数据30秒 (opens new window)
# 内网穿透
内网穿透工具nps和frp (opens new window)
保姆级教程:内网穿透工具使用总结 (opens new window)
# Caffeine Cache
缓存之王Caffeine Cache,性能比Guava更强 (opens new window)
本地缓存无冕之王Caffeine Cache (opens new window)
Caffeine Cache使用说明 (opens new window)
# selenium
selenium用法(最新版) (opens new window)
selenium配置使用chromedriver (opens new window)
Ubuntu+Chromium+Webdrive+Selenium 自动化调试环境 (opens new window)
WebMagic (opens new window) - WebMagic是一个简单灵活的Java爬虫框架。基于WebMagic,你可以快速开发出一个高效、易维护的爬虫。
# wkhtmltoimage 、wkhtmltopdf
Java服务端使用freemarker+wkhtmltoimage生成Echart图片 (opens new window)
# @Transactional
一口气说出 6种,@Transactional注解的失效场景 (opens new window)
- 1、@Transactional 应用在非 public 修饰的方法上
- 2、@Transactional 注解属性 propagation 设置错误
- 3、@Transactional 注解属性 rollbackFor 设置错误
- 4、同一个类中方法调用,导致@Transactional失效
# 事务执行完成后操作
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// code
}
});
} else {
// code
}
2
3
4
5
6
7
8
9
10
11
# idea项目脚手架
https://start.spring.io/ 只支持3.x版本的spring boot
http://start.aliyun.com 支持2.x版本的spring boot