null.equals()
会出报空指针,因该是非null
的值.equals()
Objects
的equals()
方法避免空值,完美String strOne = null;
String strTwo = null;
boolean oneFlag = Objects.equals(strOne, strTwo);
equalsIgnoreCase()
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()
避免空指针,例如遍历从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
流遍历集合中的元素进行求和操作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);
Lists.partition()
for (List<DataDto> dataDtos : Lists.partition(list, 1000)) {
dataDtoMapper.insertBatch(dataDtos);
}
<dependency>
<groupId>com.google.guavagroupId>
<artifactId>guavaartifactId>
<version>31.0.1-jreversion>
<exclusions>
<exclusion>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
exclusion>
exclusions>
dependency>
private static final Map<String, Object> TABLE_COLUMN_MAP = new HashMap<>();
// 清空集合
TABLE_COLUMN_MAP.clear();
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
Java
工厂模式请看:https://blog.csdn.net/qq_37248504/article/details/117753021Spring
收集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();
}
获取容器中的Bean
、Bean
的初始化
更多详情请看:https://blog.csdn.net/qq_37248504/article/details/113896952
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));
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());
}));
}
}
@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
社区版能满足常用的开发,支持maven
、gradle
项目,真的没有必要破解Idea
,哈哈哈哈哈哈哈哈。
使用特别Nice
基本上不用重启服务,网上都有注册码。
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
,add()
List<String> listOne = new ArrayList<>();
listOne.add("test");
listOne.add("test");
List<String> listTwo = new ArrayList<String>(){{
add("one");
add("one");
add("one");
}};
Arrays.asList()
List<String> listThree = Arrays.asList("one", "two", "three");
Stream.of()
List<String> listFour = Stream.of("testone", "testtwo", "testthree").collect(Collectors.toList());
com.google.guava
中的方法 ArrayList<String> listFive = Lists.newArrayList("one", "two", "three");
success
、error
public class ResponseInfo<T> {
/**
* 状态码
*/
private Integer code;
/**
* 信息
*/
private String message;
/**
* 返回结果
*/
private T data;
public ResponseInfo() {
}
public ResponseInfo(Integer code, String message) {
this.code = code;
this.message = message;
}
public ResponseInfo(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* 失败
*
* @param code
* @param message
* @param
* @return
*/
public static <T> ResponseInfo<T> error(Integer code, String message) {
return new ResponseInfo<>(code, message);
}
/**
* 成功
*
* @param code
* @param message
* @return
*/
public static <T> ResponseInfo<T> success(Integer code, String message) {
return new ResponseInfo<>(code, message);
}
/**
* 成功标志
*
* @param code
* @param message
* @param object
* @return
*/
public static <T> ResponseInfo<T> success(Integer code, String message, T object) {
return new ResponseInfo<>(code, message, object);
}
}
return Collections.emptyList();
return Collections.emptyMap();
return Collections.emptySet();
valueOf()
方式可以避免类型转换异常@Test
public void testOne() {
Integer one = 24;
BigDecimal two = new BigDecimal(23);
Map<String, Object> map = new HashMap<>();
map.put("one", one);
map.put("two", two);
// 报错
String strOne = (String) map.get("one");
String strTwo = (String) map.get("two");
// 正常使用
String strThree = String.valueOf(map.get("one"));
String strFour = String.valueOf(map.get("two"));
}
valueof()
方法避免转换异常// 拼接迭代器中的元素
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu");
String joinStr = String.join("','", list);
logger.info(joinStr);
// zhangsan','lisi','wangwu
@Test
public void treeSetTest() {
TreeSet<String> set = new TreeSet<String>((Comparator) (o1, o2) -> {
int length1 = String.valueOf(o1).length();
int length2 = String.valueOf(o2).length();
if (length1 == length2) return 1;
return Integer.compare(length1, length2);
});
set.add("zhangsan");
set.add("test");
set.add("lisi");
set.add("1234");
set.add("wangwu");
logger.info(String.valueOf(set));
}
Map
可以做本地的部分缓存,将常用的对象例如工具类等可以放在缓存当中,从缓存中取值,Map
作为缓存的时候,确定使用恰当。foreach
循环里进行元素的 remove/add
操作。remove
元素请使用 Iterator
方式,如果并发操作,需要对 Iterator
对象加锁。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (删除元素的条件) {
iterator.remove();
}
}
entrySet
遍历 Map
类集合 KV
,而不是 keySet
方式进行遍历。for (Map.Entry<String, String> entry : map.entrySet()) {
logger.info("键:{}", entry.getKey());
logger.info("值:{}", entry.getValue());
}
集合类 | key | value | super | 说明 |
---|---|---|---|---|
HashMap | 允许为null |
允许为null |
AbstractMap | 线程不安全 |
TreeMap | 不允许为null |
允许为null |
AbstractMap | 线程不安全 |
ConcurrentHashMap | 不允许为null |
不允许为null |
AbstractMap | 线程安全 |
Hashtable | 不允许为null |
不允许为null |
Dictionary | 锁分段技术(JDK8:CAS) |
git rm --cached 文件名
Idea
的undo commit
撤销上次的commit
重新来。reset Mixed
之前 Commit
修改的内容会保留。
reset Hard
之前Commit
修改的内容不会保留。
reset Soft
类似于 reset Mixed
,但是又区别。比如上次的commit
中有个新建的文件,当使用reset Mixed
命令时候,撤销commit
后这个新建的文件是没有进行add
操作的,文件的颜色是红色的。使用reset Soft
命令这个文件是进行了add
操作了的。
注意重写equals()
和hash()
,可以根据实际业务场景进行去重操作,例如如果商品编号相等那么断定这个商品是同一件商品。
重写对象的equals()
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (Objects.isNull(object) || getClass() != object.getClass()) return false;
Shop shop = (Shop) object;
return (Objects.nonNull(shop) ? shopCode.equals(shop.getShopCode()) : shop == null);
}
@Override
public int hashCode() {
return Objects.isNull(shopCode) ? 0 : shopCode.hashCode();
}
class Throwable;
class Exception;
class Error;
向上抛异常:最底层的代码例如工具类,直接向上抛原始异常就行了。
输出原始异常:如果是捕获到了异常,那么一定要输出原始异常的信息,如果只是输出e.getMessage
无法定位到代码出错的行数,如果是空指针错误信息都没有。
使用日志框架层:例如log4j
Objects
@Test
public void testFive() {
String str = null;
Objects.requireNonNull(str, "str is null!");
}
Assets
@Test
public void testSix() {
String str = null;
Assert.notNull(str, "str is null!");
}
其实使用
Idea
开发的时候,开启Idea
自带的代码检测,处理掉所有的告警大部分代码问题会解决,代码命名规范等可以使用阿里巴巴开发规范插件,使用SonarLint
插件可以处理一些垃圾代码,可以扫描一些静态的错误,从而提高代码质量。
DO、 DTO 、 VO
等除外UserDO
UserDTO
UserVO
CompomentFactory
AbstractPrint
基本类型会有默认值,使用包装内可以设置为null
pojo
的getter
和setter
方法里面不要增加业务逻辑。
public class MyException extends RuntimeException {
public MyException() {
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/**
* 抛出自定义异常,测试自定义异常处理器
*/
@GetMapping("/myexception")
public String createMyException() throws MyException {
throw new MyException("MyException 自定义异常信息");
}
StringBuilder strOne = new StringBuilder("test");
for (int i = 0; i < 10000000; i++) {
strOne.append(strOne);
}
final
防止重写、继承。for
循环中尝试使用同一对象处理等。Map
做常用对象的缓存Color.java
public enum Color {
RED("red", "红色"), GREEN("green", "绿色");
private String name;
private String title;
Color(String name, String title) {
this.name = name;
this.title = title;
}
public String getName() {
return name;
}
public String getTitle() {
return title;
}
}
使用反射机制会带来以下的问题:
反射基本上只适合用在编写组件时、代码分析器、RPC
等场景下使用。在使用反射机制时,如果可能,尽可能只通过反射机制实例化对象,而访问方法时,使用已知的接口或者超类。
代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束
类名使用驼峰规则,DO、BO、DTO、VO等除外
方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase
风格,必须遵从
驼峰形式。
抽象类命名使用 Abstract
或 Base
开头;异常类命名使用 Exception
结尾;测试类
命名以它要测试的类的名称开始,以 Test
结尾。
中括号是数组类型的一部分,数组定义如下:String[] args
为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词
组合来表达其意。
对于 Service
和 DAO
类,基于 SOA
的理念,暴露出来的服务一定是接口,内部的实现类用 Impl
的后缀与接口区别。
类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter
方法
private
。public
或 default
构造方法static
成员变量并且与子类共享,必须是 protected
static
成员变量并且仅在本类使用,必须是 private
static
成员变量如果仅在本类使用,必须是 private
。static
成员变量,必须考虑是否为 final
private
protected
Dbeaver
(支持各种数据库):https://dbeaver.io/Markdown
语法工具:Typora
:https://typora.io/Redis
客户端: https://gitee.com/qishibo/AnotherRedisDesktopManager