# 后端开发技巧常用规范
Posted MarlonBrando1998
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# 后端开发技巧常用规范相关的知识,希望对你有一定的参考价值。
开发技巧
equals() 方法的使用
null.equals()
会出报空指针,因该是非null
的值.equals()
- 可以使用
Objects
的equals()
方法避免空值,完美
String strOne = null;
String strTwo = null;
boolean oneFlag = Objects.equals(strOne, strTwo);
- 忽略大小写:
equalsIgnoreCase()
创建 HashMap 指定初始化大小
public HashMap(int initialCapacity)
this(initialCapacity, DEFAULT_LOAD_FACTOR);
-
initialCapacity = (需要存储的元素个数/负载因子)+1
。负载因子默认为0.75
-
当不指定
HashMap
的大小会发生多次扩容会影响效率。比如map
中有1000个元素,至少要将容量设置为1000/0.75=1333+1=1334
,如果不设置大小那么就会多次扩容,比较影响效率。 -
当无法估计大小的时候,请设置为
HashMap
的默认大小16
Optional.ofNullable().orElse() 避免空指针
通过Optional.ofNullable().orElse()
避免空指针,例如遍历从map
中拿到的某个list
,原始代码如下:
Map<String,Object> map = new HashMap<>(16);
map.put("list",null);
List<Map<String ,Object>> list = (List<Map<String, Object>>) map.get("list");
// list 会报控指针
for (Map<String, Object> item : list)
logger.info(String.valueOf(item));
- 使用
Optional
完美解决
Map<String,Object> map = new HashMap<>(16);
map.put("list",null);
List<Map<String ,Object>> list = Optional.ofNullable((List < Map < String, Object >> ) map.get("list")).orElse(new ArrayList<>());
for (Map<String, Object> item : list)
logger.info(String.valueOf(item));
- 使用
Optional
选择默认数据
User user1 = new User(1, "张三", "西安");
User user2 = new User(2, "李四", "新疆");
user1 = null;
User user = Optional.ofNullable(user1).orElseGet(() -> user2);
logger.info(user.toString());
Stream 求和
- 使用
Stream
流遍历集合中的元素进行求和操作
List<Double> doubleList = Arrays.asList(12.2, 13.45, 12.4);
double sumOne = doubleList.stream().mapToDouble(x -> x).sum();
logger.info("sumOne:", sumOne);
List<BigDecimal> decimalList = new ArrayList<>();
decimalList.add(new BigDecimal("12.3"));
decimalList.add(new BigDecimal("12.3"));
decimalList.add(new BigDecimal("12.3"));
BigDecimal bigDecimal = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
logger.info("bigDecimal:", bigDecimal.floatValue());
logger.info("bigDecimal:", bigDecimal.doubleValue());
List<Object> objectList = Arrays.asList(12, 13, 1);
int sum = objectList.stream().mapToInt(x -> (int) x).sum();
logger.info("sum:", sum);
List 切割工具
Lists.partition()
for (List<DataDto> dataDtos : Lists.partition(list, 1000))
dataDtoMapper.insertBatch(dataDtos);
- 依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
单例类或者工具类 添加私有构造方法
- 工具类或者单例类提供私有的构造函数,没有过多的功能,提供私有构造函数防止外部使用污染。
类变量(集合)应该在使用完成之后清空,避免内存泄漏
- 应该及时销毁没用的对象,如果对象过大,虚拟机没办法垃圾回收的时候,有可能造成内存泄漏,所以使用完就清空.
private static final Map<String, Object> TABLE_COLUMN_MAP = new HashMap<>();
// 清空集合
TABLE_COLUMN_MAP.clear();
使用 ThreaadLocal 后需要释放资源防止内存泄漏
private ThreadLocal<Map<String, String>> threadLocalMap = new ThreadLocal<>();
@Test
public void test1()
Map<String, String> map = new HashMap<>();
map.put("test1", "张三");
map.put("test2", "李四");
threadLocalMap.set(map);
getThreadLocalMap();
threadLocalMap.remove();
巧妙使用设计模式
-
巧妙使用接口、抽象类
-
Java
设计模式请看:https://blog.csdn.net/qq_37248504/article/details/117753021
Spring 工厂模式的结合使用
Java
工厂模式请看:https://blog.csdn.net/qq_37248504/article/details/117753021- 使用
Spring
收集Bean
对象放到一个Map
中,从这个Map
中拿到相应的对象的实例,直接上代码 - 接口
CustomerService.java
public interface CustomerService
/**
* 获取用户姓名
* @return
*/
String getUserName();
/**
* 注册
*/
void registered();
/**
* 登录
*/
void login();
- 接口的实现类:需要收集的对象实例可以有很多个实例
@Service
public class CustomerServiceOneImpl implements CustomerService
@Override
public String getUserName()
return "CustomerOne";
@Override
public void registered()
@Override
public void login()
@Service
public class CustomerServiceTwoImpl implements CustomerService
@Override
public String getUserName()
return "CustomerTwo";
@Override
public void registered()
@Override
public void login()
- 工厂方法:可以使用
set
注入、或者构造函数方式、或者从当前上下文中拿到接口的实例对象
@Component
public class CustomerFactory
/**
* 对象 Map
*/
private static final Map<String, CustomerService> OBJECT_MAP = new HashMap<>();
/**
* set 方法注入
*
* @param customerService
*/
@Autowired
private void setObjectMap(List<CustomerService> customerService)
for (CustomerService service : customerService)
OBJECT_MAP.put(service.getUserName(), service);
/**
* 获取 CustomerService 的实例
*
* @param type
* @return
*/
public static CustomerService getInstance(String type)
return OBJECT_MAP.get(type);
- 测试
/**
* Spring 工厂模式测试
*/
@Override
public void testFive()
CustomerFactory.getInstance("CustomerOne").registered();
CustomerFactory.getInstance("CustomerTwo").registered();
Spring、SpringBoot 经常使用技巧
-
获取容器中的
Bean
、Bean
的初始化 -
更多详情请看:https://blog.csdn.net/qq_37248504/article/details/113896952
Stream 流等操作时候使用方法的引用
Stream
List<String> collect = list.stream().filter("lisi"::equals).map(String::toUpperCase).collect(Collectors.toList());
collect.forEach(System.out::println);
list.removeIf("李四"::equals);
HashMap
Map<String, String> map = new HashMap<String, String>()
put("one", "one");
put("two", "one");
put("three", "one");
;
Map<String, String> mapOne = new HashMap<>();
map.forEach(mapOne::put);
logger.info(String.valueOf(mapOne));
Java 创建线程池
- 使用
ThreadPoolExecutor
创建线程池,使用线程,到处new Thread()
没有回收造成资源浪费,因该交给线程池去管理线程。
public class ThreadPooTest
private static final Logger logger = LoggerFactory.getLogger(ThreadPooTest.class);
private static final long THREAD_TIME_OUT = 60;
@Test
public void test()
// Cpu 核数
int cpuNum = Runtime.getRuntime().availableProcessors();
// 最大数
int maxSize = 2 * cpuNum + 1;
/**
* 拒绝策略:当阻塞队列和最大线程都用完之后
*
* AbortPolicy:ThreadPoolExecutor中默认的拒绝策略就是AbortPolicy。直接抛出异常。
* CallerRunsPolicy:在任务被拒绝添加后,会调用当前线程池的所在的线程去执行被拒绝的任务。
* DiscardPolicy:会让被线程池拒绝的任务直接抛弃,不会抛异常也不会执行。
* DiscardOldestPolicy:当任务呗拒绝添加时,会抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。
*/
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(cpuNum,
maxSize,
THREAD_TIME_OUT,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(20),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
poolExecutor.execute(new Thread(() ->
logger.info(Thread.currentThread().toString());
));
Spring Boot 配置全局的线程池
@Configuration
@EnableAsync
public class ThreadPoolConfig
private static final Logger logger = LoggerFactory.getLogger(ThreadPoolConfig.class);
@Bean
public Executor globalExecutor()
// 获取当前cpu核数
int cpuNum = Runtime.getRuntime().availableProcessors();
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setCorePoolSize(cpuNum);
//配置最大线程数
poolExecutor.setMaxPoolSize(cpuNum * 2);
//配置队列大小
poolExecutor.setQueueCapacity(300);
//线程存活时间
poolExecutor.setKeepAliveSeconds(60);
//配置线程池中的线程的名称前缀
poolExecutor.setThreadNamePrefix("globalExecutor");
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
poolExecutor.initialize();
logger.info(LogConstant.FLAG);
logger.info(LogConstant.LOG_SUCCESS_PREFIX + "Spring 全局线程池初始化完成......");
logger.info(JSON.toJSONString(poolExecutor));
logger.info(LogConstant.FLAG);
return poolExecutor;
- 使用
/**
* 全局线程池配置测试
*/
@Async("globalExecutor")
@Override
public void globalExecutorTest()
logger.info("test thread!");
Idea 热部署插件:Jrebel
-
Idea
社区版能满足常用的开发,支持maven
、gradle
项目,真的没有必要破解Idea
,哈哈哈哈哈哈哈哈。 -
使用特别
Nice
基本上不用重启服务,网上都有注册码。
初始化 Map
- 惯例
Map<String, String> mapTwo = new HashMap<>();
mapTwo.put("a", "b");
mapTwo.put("c", "d");
java8
新特性:双括号初始化
Map<String, String> mapOne = new HashMap<String, String>()
put("one", "testOne");
put("two", "testTwo");
put("three", "testThree");
;
com.google.guava
中的方法
ImmutableMap<String, Integer> map = ImmutableMap.of("a", 1, "b", 2, "c", 3);
logger.info(String.valueOf(map));
List 初始化
- 构造
List
,add()
List<String> listOne = new ArrayList提效小技巧——记录那些不常用的代码片段