目錄
1.深淺克隆問題
2.Mysql中可以代替左模糊或全查詢的函數(shù)方法
3.開發(fā)時(shí)需注意,使用String類的equals()方法時(shí),原則上需要左邊的變量不能為null值,避免程序執(zhí)行時(shí)出現(xiàn)空指針報(bào)錯(cuò)
4.Mysql Update的高效應(yīng)用
5.Mysql Insert 的高效應(yīng)用
6.在try-catch-finally代碼塊中return或者throw Exception時(shí)需注意的問題
7.索引過多導(dǎo)致查詢的時(shí)間不穩(wěn)定
8.JSON轉(zhuǎn)化為帶泛型的集合
9.當(dāng)時(shí)使用Map集合需要在輸出時(shí)變得有序,可以使用new LinkedHashMap()代替new HashMap()
10.關(guān)于使用String.valueOf()時(shí)需要關(guān)注的問題
11.Mysql高效新增同時(shí)更新重復(fù)數(shù)據(jù)
12.CaseInsensitiveMap應(yīng)用,v>
13.獲取List<對(duì)象>集合中對(duì)象某個(gè)字段的集合體,同時(shí)去重
14.@Builder注解用法
15.自定義線程池
16.@FeignClient在Application啟動(dòng)時(shí)拋出對(duì)象重復(fù)異常
17.新項(xiàng)目啟動(dòng)時(shí)依賴缺失問題
18.idea啟動(dòng)服務(wù)時(shí)報(bào)錯(cuò)Command line is too long
19.List<引用類型>集合排序
20.泛型方法使用
21.靜態(tài)方法調(diào)用Mapper接口
22.Mysql中g(shù)roup by 和 limit 同時(shí)使用時(shí)注意事項(xiàng):
23.stream流去重
24.Spring容器跳過指定對(duì)象初始化掃描
25. Spring自帶的入?yún)⑴锌諔?yīng)用
26.時(shí)間戳與日期戳的處理
1.深淺克隆問題
在深淺克隆時(shí)一定要注意拷貝的內(nèi)容如果是基本類型和String類型,還有Integer的-127~128范圍可以直接用淺克隆(這些類型在虛擬機(jī)都有常量池保存,不會(huì)額外新增地址保存值);如果是其他的引用類型則需要使用深克隆來操作(深克隆操作這里不做文章,具體可以參考其他大佬的文章)
2.Mysql中可以代替左模糊或全查詢的函數(shù)方法
- LOCATE('keyword',`field`,index)或者LOCATE('keyword',`field`)前者返回值=0時(shí)表示field中不存在keyword字符串,如果返回值>0表示存在,此外index表示key在field字段第index個(gè)字符開始起第一次出現(xiàn)的坐標(biāo)值,后者使用的方法相似,只是返回值默認(rèn)取第一次出現(xiàn)的坐標(biāo)值;
? ? ? ?例如:select 字段 from 表 where locate(‘檢索的串’,字段名,檢索起始位置可省略)>0
- POSITION('keyword' IN 'field')該函數(shù)的用法和LOCATE函數(shù)沒有太大的差異,返回值也是一樣的效果;
? ? ? ?例如:select 字段 from 表 where position(‘檢索的串’IN 字段名)>0
- INSTR(`field`, 'keyword') 該函數(shù)用法與①②是相近,返回值一樣的效果;
? ? ? ?例如:select 字段 from 表 where instr(字段名,‘檢索的串’)>0
注意:以上三種函數(shù)需要在檢索串的所在字段有創(chuàng)建索引情況下才能達(dá)到優(yōu)化效果
3.開發(fā)時(shí)需注意,使用String類的equals()方法時(shí),原則上需要左邊的變量不能為null值,避免程序執(zhí)行時(shí)出現(xiàn)空指針報(bào)錯(cuò)
例如:
①Field.equals(“str”)—這是錯(cuò)誤的寫法
②“str”.equals(Field)—正確的寫法
③若兩個(gè)比較的都是變量,則需提前為左邊的變量做好判空處理
if(StringUtils.isEmpty(變量1){
throw e;
}
bollean flag = 變量1.equals(變量2);
4.Mysql Update的高效應(yīng)用
當(dāng)我們需要update的表字段關(guān)聯(lián)的條件在其他時(shí),可以這么操作:
Update 表1 別名1,表2 別名2 set 字段1=更新值 where 別名1.條件字段=別名2.條件字段 and 別名1.條件字段=條件值
或者先聯(lián)查兩個(gè)表再條件查詢更新值
Update 表1 別名1 INNER(LEFT/RIGHT) JOIN 表2 別名2 ON 別名1.聯(lián)查字段=別名2.聯(lián)查字段Set 別名1.字段=值 , 別名2.字段=值 where 別名1.條件字段=值
5.Mysql Insert 的高效應(yīng)用
Insert操作時(shí)除了可以利用foreach標(biāo)簽批量插入外,可以利用查詢結(jié)果作為插入的values
例如:
INSERT INTO 表 (字段1,字段2…)SELECT 字段1,字段2… FROM 表 WHERE 條件1…
以上需要注意的是插入表的字段順序,數(shù)據(jù)類型,字段名(別名也有效)必須與查詢語句中的一致
當(dāng)insert表字段與select的表字段名,類型一致時(shí)也可以簡化為:INSERT INTO 表1 select * from 表2 where 條件1…
注意:這里更推薦使用前者指定字段,因?yàn)楫?dāng)表有更新字段時(shí)后者可能存在不匹配的情況\
6.在try-catch-finally代碼塊中return或者throw Exception時(shí)需注意的問題
如果三者中均存在return,那么執(zhí)行的順序會(huì)優(yōu)先try里的運(yùn)算表達(dá)式但不會(huì)馬上返回值,而是優(yōu)先走finally里面的運(yùn)算表達(dá)式,這樣try里return的值并不是開始想要的,而finally中return值是不生效的,而是走try或catch中的return值;此外try中出現(xiàn)異常的位置不同也會(huì)導(dǎo)致最終的結(jié)果不一樣
注意**在finally代碼塊中永遠(yuǎn)不會(huì)只是throw Exception,但是可以是用try-catch代碼結(jié)果補(bǔ)貨異常后打印到日志中**
下面是一個(gè)簡單的代碼測(cè)試:
public class test{
public static void main(String[] args) {
int result = testMethod();
System.out.println(result);
//當(dāng)異常x生效時(shí),結(jié)果為5;當(dāng)異常y生效時(shí),結(jié)果為5;當(dāng)x/y異常均不生效時(shí),結(jié)果是4
}
private static int testMethod() {
int a = 0;
try {
int b = 1;
//int x = 1 / 0;//這里模擬出了異常
a = a + b;
//int y = 1 / 0;//這里模擬出了異常
return a;
} catch (Exception e) {
int c = 2;
a = a + c;
System.out.println("出問題了:" + e.getMessage());
return a;
} finally {
int d = 3;
a = a + d;
return a;
}
}
}
7.索引過多導(dǎo)致查詢的時(shí)間不穩(wěn)定
當(dāng)表中索引的數(shù)量很多,且explain查詢語句時(shí),發(fā)現(xiàn)某個(gè)表的可能索引有很多個(gè),此時(shí)可以在表名后面增加一個(gè)force index(索引名)來強(qiáng)制走某一個(gè)索引,這樣就可以節(jié)約的mysql在查詢時(shí)增加檢索索引的時(shí)間,提高性能,并且能穩(wěn)定查詢時(shí)間
例如:
select 字段 from 表名 force index(索引名) where 條件1 and 條件2 ...
8.JSON轉(zhuǎn)化為帶泛型的集合
引用類型<T>??obj = JSON.parseObject(JSON.toJSONString(Object),new TypeReference<引用類型<T>>(){});
常用與JsonRespone<T>,PageResult<T>,Map<K,V> 這種類型的jsonString -> 對(duì)象
9.當(dāng)時(shí)使用Map集合需要在輸出時(shí)變得有序,可以使用new LinkedHashMap()代替new HashMap()
public class test {
public static void main(String[] args) {
Map<Integer, Object> map1 = new HashMap();
map1.put(7, "c");
map1.put(5, "a");
map1.put(6, "b");
System.out.println(map1);//輸出結(jié)果不會(huì)按照key的put順序輸出而是一個(gè)隨機(jī)順序
Map<Integer, Object> map2 = new LinkedHashMap();
map2.put(3, "c");
map2.put(1, "a");
map2.put(2, "b");
System.out.println(map2);//輸出結(jié)果會(huì)按照key的put順序進(jìn)行輸出
}
}
10.關(guān)于使用String.valueOf()時(shí)需要關(guān)注的問題
情況一:
String a = String.valueOf(null);
以上再運(yùn)行時(shí)會(huì)拋出空指針異常
情況二:
Long b = null;? ?String a = String.valueOf(b);
綜上所述:代碼在執(zhí)行時(shí)并不會(huì)拋出空指針異常,但是會(huì)把null值轉(zhuǎn)化為”null”字符串,從某種意義上會(huì)改變?cè)械拇a邏輯
11.Mysql高效新增同時(shí)更新重復(fù)數(shù)據(jù)
INSERT INTO 表名 (字段1...) VALUES (值1...) ON DUPLICATE KEY UPDATE 字段1=values(字段1), 字段2=values(字段2);
注意:以上sql需要配合唯一索引使用,并且唯一索引設(shè)定有可能會(huì)存在沖突問題
12.CaseInsensitiveMap<k,v>應(yīng)用
CaseInsensitiveMap<k,v>與常規(guī)的HashMap<k,v>不同的是,CaseInsensitiveMap的key值是不區(qū)分大小寫的
13.獲取List<對(duì)象>集合中對(duì)象某個(gè)字段的集合體,同時(shí)去重
集合對(duì)象.stream().map(對(duì)象別名(自定義即可)->別名.get字段).distinct().collect(Collectors.toList);
14.@Builder注解用法
在實(shí)體類上添加@Builder(toBuilder = true)注解,可以在創(chuàng)建對(duì)象時(shí)賦值或者重新對(duì)一個(gè)對(duì)象重新賦值,用法上類似@Accessors(chain = true)與鏈?zhǔn)郊虞d,例如:
①創(chuàng)建新對(duì)象
引用類型 對(duì)象 = 引用類型.builder().屬性1(value1).屬性2(value2).build();
②重新賦值對(duì)象
對(duì)象.toBuilder().屬性1(value1).屬性2(value2).build();
15.自定義線程池
ThreadPoolExecutor(corePooSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);
參數(shù)說明:
1.corePoolSize -- 核心線程數(shù)
2.maxmunPoolSize -- 最大核心線程數(shù)
3.keepAliveTime -- 閑時(shí)線程最大存貨時(shí)間
4.unit -- 單位(用于定義最大存活時(shí)間)
5.workQueue -- 隊(duì)列規(guī)則
6.threadFactory -- 線程池工廠
7.handler -- 線程異常類型
16.@FeignClient在Application啟動(dòng)時(shí)拋出對(duì)象重復(fù)異常
當(dāng)同一個(gè)服務(wù)下有多個(gè)feign對(duì)象配置了相同的value值(調(diào)用同一個(gè)服務(wù)名),正常情況下會(huì)因?yàn)閷?duì)象創(chuàng)建沖突導(dǎo)致異常,這種時(shí)候有兩種方法解決:
①在yml中配置(允許覆蓋重名的對(duì)象創(chuàng)建,但是這樣就可能不能實(shí)現(xiàn)feign的相互獨(dú)立):
spring:
? main:
? ? allow-bean-definition-overriding: true
②在每個(gè)@FeignClient中添加contextId屬性值,作為對(duì)象創(chuàng)建時(shí)的區(qū)分
17.新項(xiàng)目啟動(dòng)時(shí)依賴缺失問題
新項(xiàng)目中明明Maven已經(jīng)正常下載完所有的依賴了,但是在啟動(dòng)服務(wù)時(shí)還是會(huì)出現(xiàn)依賴缺失等異常的問題?
這是因?yàn)閟pring在啟動(dòng)時(shí)會(huì)忽略pom.xml文件中帶<scope>provided</scope>標(biāo)簽的依賴,最終導(dǎo)致依賴出現(xiàn)缺失的問題,解決方法:
①找到這些依賴并注釋該標(biāo)簽內(nèi)容,但需要注意某些項(xiàng)目在上線構(gòu)建時(shí)并不需要這些依賴,所以在上線記得要把注釋恢復(fù)回來
②(推薦)在idea的啟動(dòng)configurations配置中增加provideds屬性配置如圖:
18.idea啟動(dòng)服務(wù)時(shí)報(bào)錯(cuò)Command line is too long
idea啟動(dòng)時(shí)報(bào)錯(cuò):Error running xxxxx. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.
這里解決方法有兩個(gè):
①(推薦)在idea的啟動(dòng)configurations配置如圖:
②在項(xiàng)目的.idea/workspace.xml文件中,找到<component name="PropertiesComponent">,后面在添加一行<property name="dynamic.classpath" value="true" />
19.List<引用類型>集合排序
//按照List中對(duì)象的字段屬性升序
list.sort(Comparator.comparing(引用類型::get字段))
//按照List中對(duì)象的id屬性降序
list.sort(Comparator.comparing(引用類型::get字段).reversed());
//多條件升序
list.sort(Comparator.comparing(引用類型::get字段1).thenComparing(引用類型::get字段2));
//id降序
list.sort(Comparator.comparing(引用類型::get字段1).reversed().thenComparing(引用類型::get字段2))
20.泛型方法使用
泛型方法的聲明:
修飾符 <T> 返回值 方法名(參數(shù)...){...}
*注意<T>是表示當(dāng)前方法是一個(gè)泛型方法,一般在修飾符和返回值中間進(jìn)行聲,明
21.靜態(tài)方法調(diào)用Mapper接口
我們都知道靜態(tài)方法只能調(diào)用靜態(tài)資源,當(dāng)靜態(tài)方法中想調(diào)用Mapper接口時(shí),我們是不能在Mapper前面添加static修飾的,那么想要調(diào)用Mapper就得換一個(gè)思路,Spring在實(shí)例化一個(gè)bean時(shí)會(huì)對(duì)這個(gè)bean中的屬性進(jìn)行賦值,既然Mapper無法成為靜態(tài)資源那么我們就可以將這個(gè)工具類本身作為一個(gè)靜態(tài)資源(對(duì)象)去調(diào)用,例如:
@Component
public class DemoUtils{
@Autowired
private XxMapper xxMapper;
private static DemoUtils demoUtils;
//自定義實(shí)例化
@PostConstruct
public void init() {
demoUtils = this;
demoUtils.xxMapper = this.xxMapper;
}
public static void method1(參數(shù)1){
//利用已實(shí)例化好的靜態(tài)對(duì)象進(jìn)行調(diào)用Mapper
demoUtils.xxMapper.xx方法(參數(shù)1);
}
}
22.Mysql中g(shù)roup by 和 limit 同時(shí)使用時(shí)注意事項(xiàng):
在Mysql中我們經(jīng)常會(huì)使用group by對(duì)數(shù)據(jù)進(jìn)行分組查詢,但是有一種現(xiàn)象需要注意的,即當(dāng)我們?cè)诓樵儠r(shí)如果表的可能索引不是唯一的,且查詢時(shí)join 聯(lián)查的條件 和 where查詢的條件使用的索引不一致,此時(shí)如果group by 的字段涉及到這個(gè)表時(shí)?,我們?cè)谶M(jìn)行l(wèi)imit 分頁查詢那么可能會(huì)出現(xiàn)那么一種現(xiàn)象: group by 后加了limit 查詢會(huì)很慢,這是因?yàn)間roup 和 limit 同時(shí)使用時(shí)會(huì)重新掃描sql上所有的關(guān)聯(lián)表,最終即使limit 10條數(shù)據(jù)也會(huì)比原來的sql慢上許多;
解決方法:
①使用強(qiáng)制索引(硬核安心),如:
select * from t1 force index(xxx索引) left join t2 on xxx條件 where xxx條件 group by xx字段 limit 0,10
②group by 和 limit 隔離使用,即將原有的sql作為一個(gè)子查詢?cè)偃imt 分頁,如:
select * from (...含了group by的sql) limit 0,10
23.stream流去重
一個(gè)已知集合List<引用類型>? A,根據(jù)A集合中的每個(gè)對(duì)象的特定字段作為唯一主鍵去重
①單字段去重
A.stream().collect(Collectors.toMap(引用類型::getXX字段,e->e)).values().stream().collect(Collectors.toList());
②多字段去重(通用型表達(dá),只get一個(gè)字段相當(dāng)于①的表達(dá)式效果)
A.stream().collect(Collectors.toMap(e->e.get字段1()+e.get字段2(),e->e)).values().stream().collect(Collectors.toList());
說明: toMap()里面有兩段表達(dá)時(shí),以","號(hào)分隔,第一段表示獲取哪些字段作為主鍵去重,②中的e可以任意命名,表示A集合中的每個(gè)元素的變量名;第二段表示去重前的引用類型和去重后需要得到的內(nèi)容,->e.get字段()可以指定某些字段
在使用流去重時(shí)還需要注意,當(dāng)選取的唯一主鍵(單字段或多字段)不是一對(duì)一時(shí),這個(gè)表達(dá)式編譯時(shí)不會(huì)異常,但運(yùn)行時(shí)會(huì)拋出Duplicate key...的異常,意思就是出現(xiàn)了一對(duì)多的關(guān)系不可以無法的到Map<k,v>的結(jié)構(gòu),解決方法:
方法一:
Collectors.toMap(...)改為Collectors.groupBy(e->e.get字段1()+get字段2()..),最終可獲取到一個(gè)Map<k,List<T>>的結(jié)構(gòu),這樣的話,去重?cái)?shù)據(jù)時(shí)還要做一次遍歷封裝去重后的數(shù)據(jù)
方法二(推薦):
優(yōu)化Collectors.toMap(e->e.get字段1()+get字段2()..,e->e,(key1,key2)->key1或key2),這里(key1,key2)是固定寫法表示出現(xiàn)了重復(fù)數(shù)據(jù),當(dāng)表達(dá)式->key1時(shí)表示重復(fù)數(shù)據(jù)只保留前者,同理key2代表后者
24.Spring容器跳過指定對(duì)象初始化掃描
我們?cè)诜植际巾?xiàng)目中經(jīng)常都是建立子Maven工程集成于父級(jí)工程的pom.xml,但是在父級(jí)工程中會(huì)存在很多公共的依賴,而一些子級(jí)工程是不需要的,例如:MYBATIS的JDBC依賴,如果子級(jí)工程沒有在在yml文件中聲明數(shù)據(jù)庫連接的配置,在啟動(dòng)spring容器時(shí)就會(huì)報(bào)錯(cuò),此時(shí)我們又不想增加無用的配置在yml中,我們可以在這個(gè)子級(jí)的啟動(dòng)類的@SpringBootApplication注解上exclude={類名.class},即可跳過這些類的對(duì)象初始化
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
@EnableEurekaClient
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
這里的DataSourceAutoConfiguration.class 和?DruidDataSourceAutoConfigure.class都是用于數(shù)據(jù)庫連接的配置對(duì)象,不一定兩個(gè)都需要跳過,具體看父級(jí)的依賴引入,這里就不做過多的解釋了
25. Spring自帶的入?yún)⑴锌諔?yīng)用
在實(shí)現(xiàn)接口時(shí),我們經(jīng)常都需要對(duì)某些關(guān)鍵入?yún)⑦M(jìn)行判空,防止空指針異常的出現(xiàn),但有些公共的入?yún)⒍际峭粋€(gè)實(shí)體類并且關(guān)鍵入?yún)⒆侄味际且粯拥?我們?cè)诿總€(gè)接口實(shí)現(xiàn)都寫一次就會(huì)出現(xiàn)許多重復(fù)的代碼,Spring框架就自帶了@Valid 和 @Valided注解對(duì)入?yún)⒅械膶?shí)體類進(jìn)行判空,以下是代碼實(shí)現(xiàn):
//實(shí)體類的代碼
@Data
public class DemoDto{
@NotEmpty
private String name;
@NotNull
private Long id;
}
?這里在使用時(shí)需要注意數(shù)據(jù)類型
@NotEmpty表示 不能為空串和null值 ,一般用在字符串類型上
@NotNull表示 不能為空,任意的引用類型都可以使用
//控制層代碼
@RestController
public class DemoController{
@PostMapping("/test/demo")
public JsonResponse testDemo(@Valid @RequestBody DemoDto param){
return JsonResponse.success("OK");
}
}
這里需要注意@Valid 和 @Valided注解需要配合實(shí)體類上的注解一起使用,否則容器不知道這個(gè)實(shí)體類需要校驗(yàn)?zāi)男┳侄螢榉强杖雲(yún)?/p>
26.時(shí)間戳與日期戳的處理
在Excel導(dǎo)入時(shí),有時(shí)因?yàn)槟承└袷脚渲脤?dǎo)致了日期類型的時(shí)間 會(huì) 序列成了 數(shù)字格式的 字符串,這種字符也是就是我們常見的時(shí)間戳,但是時(shí)間 也是有幾種的,目前了解的場(chǎng)景有3中:
①5位數(shù) 這種是因?yàn)槿掌诟袷街兄挥心暝氯辙D(zhuǎn)化導(dǎo)致得到了一個(gè)天數(shù),可以理解為日期戳,而日期戳的換算如下:
Date date = new Date();
Calendar calendar = Calendar.getInstance();
//獲取日期偏移值
long localOffset = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000); //系統(tǒng)時(shí)區(qū)偏移 1900/1/1 到 1970/1/1 的 25569 天
date.setTime(((Long.parseLong(val) - 25569) * 24 * 3600 * 1000 + localOffset));
//換算得成13位數(shù)的時(shí)間戳
long timestamp = date.getTime();
②10位數(shù) 這種格式一般是年月日時(shí)分秒,去到秒級(jí)的的時(shí)間戳,轉(zhuǎn)化如下文章來源:http://www.zghlxwxcb.cn/news/detail-452170.html
//10位時(shí)間戳
String timestamp = "1702632914";
Date date = new Date(Long.parseLong(timestamp)*1000);
//獲取13位時(shí)間戳
long newTimestamp = date.getTime();
③13位數(shù) 這種就是毫秒級(jí)別的時(shí)間戳,轉(zhuǎn)換如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-452170.html
// 13位時(shí)間戳
long timestamp = 1634567890123L;
//時(shí)間格式化對(duì)象,可以自定義 時(shí)間表達(dá)式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 將13位時(shí)間戳轉(zhuǎn)化為Date對(duì)象
Date date = new Date(timestamp);
//格式化的時(shí)間字符串
String dateTimeStr = sdf.format(date);
//注意:以上可以通過統(tǒng)一轉(zhuǎn)為13位的時(shí)間戳得到正確的 格式化Date對(duì)象 或者 時(shí)間字符串
到了這里,關(guān)于JAVA開發(fā)中常見問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!