1. 使用合适的数据结构
选择合适的数据结构对提高代码效率至关重要。
示例:使用HashMap优化查找
// 不推荐的做法:使用List进行查找 List 查找元素,是通过索引慢
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
if (list.contains("banana")) {
// 处理逻辑
}
// 推荐的做法:使用HashMap提高查找效率 HashSet 的底层是 HashMap ,直接相等与
Set<String> set = new HashSet<>(Arrays.asList("apple", "banana", "cherry"));
if (set.contains("banana")) {
// 处理逻辑
}
set.contains("banana") == map.get("banana")
2. 避免重复代码
重复代码会使得程序难以维护,使用方法或类重构可以有效解决这一问题。
示例:提取重复代码到方法
// 重复代码示例
public void processUser(User user) {
if (user != null && user.isActive()) {
// 处理逻辑
}
}
// 优化后
public void processUser(User user) {
if (isValidUser(user)) {
// 处理逻辑
}
}
private boolean isValidUser(User user) {
return user != null && user.isActive();
}
3. 利用Java 8特性
Java 8引入了许多新特性,如Lambda表达式和Stream API,它们可以使代码更加简洁高效。
示例:使用Stream API处理集合
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
4. 理解并发编程
在多线程和并发编程中,正确管理资源和线程是提高性能的关键。
示例:可以使用Java 8 的 CompletableFuture
// 异步把上个版本的数据 批量插入到 历史表
CompletableFuture.runAsync(() -> {
MyBatisBatchExecutorUtil.batchCommit(PzryMapper.class, INSERT_HISTORY, historyList);
MyBatisBatchExecutorUtil.batchCommit(PzryMapper.class, BATCH_HISTORY_INSERT_LD, historyLdData);
});
// 异步调用一些方法(记录操作日志)
CompletableFuture.runAsync(() -> logService.addLog(LogOperationYeMianEnum.getContent(2), logType, builder, isSucess, userId));
5.使用全局异常类
可以使用全局异常处理类来替换写不完的 try catch
示例: @RestControllerAdvice
原本:
@GetMapping("/add2")
public String add2() {
String result = "成功";
try {
int a = 10 / 0;
} catch (Exception e) {
result = "数据异常";
}
return result;
}
使用后:
@GetMapping("/add2")
public String add2() {
String result = "成功";
int a = 10 / 0;
return result;
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
if (e instanceof ArithmeticException) {
return "数据异常";
}
if (e != null) {
return "服务器内部异常";
}
return null;
}
}
6. 多使用工具类方法
可以多使用一些工具类方法来判断集合,字符串,对象是否为空
示例: Objects,Strings,StringUtils, CollectionUtils,ObjectUtils
Objects.nonNull(new Ld());
Objects.isNull(new Ld());
Objects.equals(new Ld(),new Ld());
Strings.isNullOrEmpty("");
StringUtils.isEmpty();
CollectionUtils.isEmpty(new HashMap<>());
CollectionUtils.isEmpty(new ArrayList<>());
CollectionUtils.isEmpty(new HashSet<>());
List<Object> list = new ArrayList<>();
list.add("111");
System.out.println(ObjectUtils.isEmpty(list));
7. 字符串拼接
替换传统的 + “” +
示例:String.format
String.format("%s(%s)", name.getName(), name.getNetId())
8. 优化一些码值的转换
替换传统的if else 判断存值
示例:使用 map 或 枚举
//如果是 例行= 0 非例行= 1 OA申请=2
Map<String, String> map= new HashMap<>(16);
map.put("例行", "0");
map.put("非例行", "1");
map.put("OA申请", "2");
yxThingsType.setIsRoutine(map.getOrDefault(yxThingsType.getIsRoutine(), ""));
9. 使用静态常量替换魔法值,字符串
private static final String INSERT_HISTORY = "insertHistory";
private static final Integer MAX_DRAFT_COUNT = 5;
10. 批量插入几百条,几千条数据库时使用工具类
穿透的批量插入,当数据量过多的时候批量插入的时间多长
示例:使用底层 sqlSessionFactory 的批量插入
工具类1:
package com.ly.cloud.util;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import com.google.common.collect.Lists;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @Author
* @Date Created in 2023/12/25 15:57
* @DESCRIPTION: mybatis快速批量插入 数据 工具类
* @Version V1.0
*/
@Component
public class MyBatisBatchExecutorUtil {
private static final Logger logger = LoggerFactory.getLogger(MyBatisBatchExecutorUtil.class);
@Resource
private SqlSessionFactory sqlSessionFactory;
private static MyBatisBatchExecutorUtil utils;
@PostConstruct
public void init() {
utils = this;
utils.sqlSessionFactory = this.sqlSessionFactory;
}
/**
* 批量提交数据
*
* @param mapperClass Mapper 类
* @param dataList 要提交的数据列表
*/
public static <T> void batchCommit(Class<?> mapperClass, String mybatisSqlId, List<T> dataList) {
if (dataList == null || dataList.isEmpty()) {
return;
}
SqlSession session = null;
int commitCountEveryTime = 500;
try {
long startTime = System.currentTimeMillis();
session = utils.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
List<List<T>> groupList = Lists.partition(dataList, commitCountEveryTime);
for (List<T> tempList : groupList) {
session.insert(mapperClass.getName() + "." + mybatisSqlId, tempList);
}
session.commit();
session.clearCache(); // 移动到循环结束后执行
long endTime = System.currentTimeMillis();
logger.info("批量插入数据耗时:" + (endTime - startTime) + "毫秒");
} catch (Exception e) {
logger.error("batchCommit error!", e);
if (session != null) {
session.rollback();
}
} finally {
if (session != null) {
session.close();
}
}
}
}
使用示例:
INSERT_HISTORY === 》 对应的mapper 类的方法名 (mybatis 的id )
currentData === 》 对应的数据集合
MyBatisBatchExecutorUtil.batchCommit(NewYxThingsTypeMapper.class, INSERT_HISTORY, currentData);
工具类2:
package com.example.juc.utils.dataUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.function.BiFunction;
/**
* @author 12926
* @CreatTime: 2022/7/27 10:53
*/
@Component
public class MybatisBatchUtils {
/**
* 每次处理1000条
*/
private static final int BATCH_SIZE = 1000;
@Resource
private SqlSessionFactory sqlSessionFactory;
private static MybatisBatchUtils utils;
@PostConstruct
public void init() {
utils = this;
utils.sqlSessionFactory = this.sqlSessionFactory;
}
/**
* 批量处理修改或者插入
*
* @param data 需要被处理的数据
* @param mapperClass Mybatis的Mapper类
* @param function 自定义处理逻辑
* @return int 影响的总行数
*/
public static <T,U,R> int batchUpdateOrInsert(List<T> data, Class<U> mapperClass, BiFunction<T, U, R> function) {
int i = 1;
SqlSession batchSqlSession = utils.sqlSessionFactory.openSession();
batchSqlSession.getConfiguration().setDefaultExecutorType(ExecutorType.BATCH);
try {
U mapper = batchSqlSession.getMapper(mapperClass);
int size = data.size();
for (T element : data) {
function.apply(element,mapper);
if ((i % BATCH_SIZE == 0) || i == size) {
System.out.println(batchSqlSession.flushStatements());
}
i++;
}
// 非事务环境下强制commit,事务情况下该commit相当于无效
batchSqlSession.commit(!TransactionSynchronizationManager.isSynchronizationActive());
} catch (Exception e) {
batchSqlSession.rollback();
throw new RuntimeException(e);
} finally {
batchSqlSession.close();
}
return i - 1;
}
}
//使用方法
MybatisBatchUtils.batchUpdateOrInsert(list, UserMapper.class,
(user, userMapper) -> userMapper.insert(user));
@Mapper
public interface UserMapper {
List<User> getUsersList();
int insert(@Param("user") User user);
}
11. 获取接口的请求头信息
使用工具类获取,每次在只需要一行代码
示例:
原来每个请求:@RequestHeader("loginUserId") String loginUserId
@ApiOperation("查询流程[类型]列表(本地数据源)")
@PostMapping("/listInstancesTypeByLocal")
public WebResult<List<InstancesStatusVo>> listInstancesTypeByLocal(@RequestBody FlowGetInstanceByTypeDto flowGetInstanceByTypeDto,
@RequestHeader("loginUserId") String loginUserId) {
return WebResult.ok(yxMyThingsService.listInstancesTypeByLocal(flowGetInstanceByTypeDto, loginUserId));
工具类:
public class LoginUserUtil {
public static String getLoginUserId() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = null;
if (requestAttributes != null) {
request = ((ServletRequestAttributes) requestAttributes).getRequest();
}
// 子线程共享
RequestContextHolder.setRequestAttributes(requestAttributes, true);
if (request != null) {
return request.getHeader("loginUserId");
}
return null;
}
}
//调用:
LoginUserUtil.getLoginUserId
12. 遍历Map 的时候,使用 EntrySet 方法
使用 EntrySet 方法,可以直接返回 set 对象,直接拿来用即可;而使用 KeySet 方法,获得的是key 的集合,需要再进行一次 get 操作,多了一个操作步骤,所以更推荐使用 EntrySet 方式遍历 Map。
Set<Map.Entry<String, String>> entryseSet = nmap.entrySet();
for (Map.Entry<String, String> entry : entryseSet) {
System.out.println(entry.getKey()+","+entry.getValue());
}
13.为集合对象中的每个元素赋值(序号)
IntStream.rangeClosed(1, departmentList.size())
.forEach(i ->
departmentList.get(i - 1).setMyNumber(String.valueOf(i)));
14. 减少集合循环次数
在开发比较俩个集合的案例很多
示例:
反例
for(User user: userList) {
for(Role role: roleList) {
if(user.getRoleId().equals(role.getId())) {
user.setRoleName(role.getName());
}
}
}
正例
Map<Long, List<Role>> roleMap = roleList.stream().collect(Collectors.groupingBy(Role::getId));
for (User user : userList) {
List<Role> roles = roleMap.get(user.getRoleId());
if(CollectionUtils.isNotEmpty(roles)) {
user.setRoleName(roles.get(0).getName());
}
}
15. 使用BigDecimal 进行小数点的加减
private String covertString(String pzrySmallBbh) {
if (!StringUtils.isEmpty(pzrySmallBbh)) {
// 将字符串转换为 BigDecimal 类型
BigDecimal number = new BigDecimal(pzrySmallBbh);
// 每次加 0.01
number = number.add(new BigDecimal("0.01"));
// 将结果转换回字符串
return number.toString();
}
return null;
}
16. 多个线程往同一个集合中写数据时
使用:CopyOnWriteArrayList
List<Object> list = new CopyOnWriteArrayList<>();
Set<Object> list = new CopyOnWriteArraySet<>();
Map<String,String> map2 = new ConcurrentHashMap<>()
17. 集合复制时修改复制后的集合
反例: 这样会把 yxAdminList 这个集合的 setYxThingNo 也值为空;
List<YxAdmin> yxAdminListTwo = new ArrayList<>(yxAdminList);
yxAdminListTwo.forEach(vo -> vo.setYxThingNo(""));
正例:
List<ListCopy> addALL = new ArrayList<>();
addALL.addAll(list);
addALL.forEach(vo -> vo
.setName(""));
或者使用for循环
List<YxAdmin> yxAdminListTwo = new ArrayList<>();
for (YxAdmin vo : yxAdminList) {
YxAdmin copiedAdmin = new YxAdmin();
copiedAdmin.setName(vo.getName());
copiedAdmin.setDepartment(vo.getDepartment());
copiedAdmin.setYxThingNo("");
yxAdminListTwo.add(copiedAdmin);
}
18. 将list<String> 转成字符串
List<String> objects = new ArrayList<>();
String name = String.join(",", objects);
19. 学会使用三目运算符
反例
String title;
if (isMember(phone)) {
title = "会员";
} else {
title = "游客";
}
正例
String title = isMember(phone) ? "会员" : "游客";
20. 使用增强for 替换普通for 循环
for (JsonElement element : dataArray) {
JsonObject itemObject = element.getAsJsonObject();
String title = itemObject.get("Title").getAsString();
System.out.println("Title:----" + title);
}
21. 利用 Map 的 computeIfAbsent 方法
利用 Map 的 computeIfAbsent 方法,可以保证获取到的对象非空,从而避免了不必要的空判断和重新设置值。
普通写法:
Map<Long, List<UserDO>> roleUserMap = new HashMap<>();
for (UserDO userDO : userDOList) {
Long roleId = userDO.getRoleId();
List<UserDO> userList = roleUserMap.get(roleId);
if (Objects.isNull(userList)) {
userList = new ArrayList<>();
roleUserMap.put(roleId, userList);
}
userList.add(userDO);
}
使用利用 Map 的 computeIfAbsent 方法
Map<Long, List<UserDO>> roleUserMap = new HashMap<>();
for (UserDO userDO : userDOList) {
roleUserMap.computeIfAbsent(userDO.getRoleId(), key -> new ArrayList<>())
.add(userDO);
}
22.stream 并行流适时使用
// 使用stream 并行流处理查询结果,检查是否有重复数据 提高查询效率
if (admins.parallelStream().anyMatch(vo -
> !CollectionUtils.isEmpty(
pzPeopleMapper.isExitYxAdmin(vo.getName(), vo.getDepartment())))) {
// 只要匹配到有一条重复数据,直接返回 false
return false;
}
后续。。。。持续更新