前言
在項目中隨手把haseMap改成了currenHaseMap差點被公司給開除了。
判斷相等
字符串判斷相等
String str1 = null;
String str2 = "java金融";
// str1.equals(str2); 錯誤的寫法
str2.equals(str1); // 常量寫前面
Objects.equals(str1, str2);// 借助jdkUtil工具類
StringUtils.equals(str1,str2); // 自定義工具類
- 字符串判斷相等我們記住一定要常量寫前面。
- 借助jdk提供的util幫助類(Objects)。
- 自定義工具類,進行判空處理。
包裝類判斷相等
Integer n1 = 100;
Integer n2 = 100;
System.out.println(n1 == n2);//true
System.out.println(n1.equals(n2));//true
Integer n3 = 200;
Integer n4 = 200;
System.out.println(n3 == n4);//false
System.out.println(n3.equals(n4));//true
為什么n3== n4 是false呢?由於包裝類的緩存機制。
包裝類的比較用equals去判斷。
最推薦的還是用工具類去判斷。例如上面的列子如果n3=null的話n3.equals(n4)這時候就會拋出npe了。如果用工具類的話就不會存在這種情況。總之一句話判斷相等如果不願意去判空(偷懶、代碼也不好看)就借助工具類。合理使用工具類可以使你的代碼減少不必要的npe。
三目運算符
這個常見的坑的話就是由於自動拆箱導致的 NPE 異常。這個阿里巴巴開發手冊(需要這個手冊可以關注公眾號回復"JAVA")說的很明白了。
BigDecimal
禁止使用浮點數double,float的初始化
double d = 1.001;
float f = 1.001f;
BigDecimal bigDecimal1 = new BigDecimal(d);
BigDecimal bigDecimal2 = new BigDecimal(f);
System.out.println(bigDecimal1);
System.out.println(bigDecimal2);
輸出結果
1.000999999999999889865875957184471189975738525390625
1.00100004673004150390625
這個結果是不是跟我們所期望的1.001有點不一樣。
float和double可以用於工程計算科學計算,他們會有精度丟失,這是由於浮點運算器的結構導致的,但是在金融領域一旦精度出現問題就意味着可能是嚴重的現實經濟損失,所以普通的那些數值型一般不會在這個場景下使用。
所以涉及金錢的計算一定不要使用float和double。使用BigDecimal並且一定要用String來構造。 上面的列子我們可以這樣來初始化 new BigDecimal("1.001")。
進行除法運算時必須要設置保留小數位
BigDecimal a = new BigDecimal("1");
System.out.println(a.divide(new BigDecimal(3)));
輸出
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1690)
at com.workit.demo.antisper.Test.main(Test.java:11)
解決辦法:使用如下兩個函數設置精度
- divide(num, scale)
- divide(num, scale, roundingMode)
BigDecimal a = new BigDecimal("1");
System.out.println(a.divide(new BigDecimal(3), 2,BigDecimal.ROUND_HALF_UP));
字符串分隔(別忘了轉義)
String str = "java|php|c++";
String[] split = str.split("|");
for(String s:split){
System.out.println(s);
}
輸出結果
j
a
v
a
|
p
h
p
|
c
+
+
結果並不是我們所期待的,java、php、c++。
解決辦法我們對|進行轉義分割,代碼改為 String[] split = str.split("\|");結果就正確了。
String的split方法需要轉義的字符串:. $ | ( ) [ { ^ ? * + \ 共12個特殊字符,遇到以這些字符進行分割字符串的時候,需要在這些特殊字符前加雙反斜杠\ \。
Arrays.asList 需要謹慎使用
下面列舉一些常用但是卻與我們所期待的結果不一樣的用法。
將基本類型數組作為asList的參數
int[] array = {1,2,3};
List list = Arrays.asList(array);
System.out.println(list.size()); //1
輸出的結果是1不是3哦是不是跟想象的有點不一樣?原因如下:
由於Arrays.ArrayList參數為可變長泛型,而基本類型是無法泛型化的,所以它把int[] array 數組當成了一個泛型對象,所以集合中最終只有一個元素array 。
將數組作為asList參數后,修改數組或List
String[] array = {"歡迎","關注","java金融"};
List list = Arrays.asList(array);
array[0] ="修改數組第一個元素";
list.set(2,"修改集合第三個元素");
System.out.println(Arrays.toString(array));
System.out.println(list.toString());
輸出結果
[修改數組第一個元素, 關注, 修改集合第三個元素]
[修改數組第一個元素, 關注, 修改集合第三個元素]
是不是也與我們所期待的不一樣。修改了數組奧了的值居然影響到了集合里面的值。原因如下:
由於asList產生的集合元素是直接引用作為參數的數組,所以當外部數組或集合改變時,數組和集合會同步變化,這在平時我們編碼時可能產生莫名的問題。
數組轉換為集合后,進行增刪元素。
String[] array = {"歡迎","關注","java金融"};
List list = Arrays.asList(array);
list.add("java金融");
System.out.println(list.toString());
輸出結果:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
拋出異常原因:由於asList產生的集合並沒有重寫add,remove等方法,所以它會調用父類AbstractList的方法,而父類的方法中拋出的卻是異常信息。
當我們使用Arrays.asList 產生的集合時候,需要謹慎的去使用。如果需要對集合進行操作的時候我們可以通過 List list = new ArrayList(Arrays.asList(array)); 來進行使用。
currenHaseMap注意 key和value的null值
String key = "java金融";
Map<String,Object> map = new ConcurrentHashMap<>();
map.put("1","2");
map.put(key,null);// Exception in thread "main" java.lang.NullPointerException
記得剛開始工作的時候,我負責的一個管理系統里面有一個關於省份的緩存,用HashMap來存的。大概就是項目一起動,然后就從db里面把省份信息加載到HashMap里面,以后需要用到省份信息直接從HashMap里面取,HashMap不是線程不安全嗎?然后我反手就把它改成了currenHaseMap。測試環境測試沒問題,然后就跟着其他功能上線。上完線之后也沒有去回歸關於省份的這一塊內容,然后就下班了。第二天上班運營反映有部分注冊用戶的省份信息沒了。leader就找我昨天有沒有改過關於省份的代碼,我說就改了一個currenHaseMap。leader先讓昨天上線代碼回退,一回退省份信息就有了。后面經過仔細排查原來生產數據庫有一條省份信息是空的。然后加載那條空的省份信息到currenHaseMap就報空指針了,在這條空記錄后面信息就沒加載到currenHaseMap了。幸好是內網管理系統沒有造成太大的影響 。
string.valueof
String userName= String.valueOf(parmMap.get("userName"));
if(StringUtils.isNotBlank(userName)) {
sql.append(" and tt.userName like %").append(userName);
}
這里的 parmMap.get("userName") 如果是 null , 那么這里的 userName就是 “null” ,這是一個值為 null 的字符串。導致數據會拼接到SQL 中,導出出錯。為什么會這樣我們看下源碼就知道了。
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
所以轉字符串的時候我們要根據實際的情況來選擇合適的方法。
總結
本文列舉了一些對於java常見的一些可能稍微不注意就會采坑的一些知識點。還有其他更多需要注意的知識點也歡迎大家來補充。其實這些常見的采坑基本上只要去看下源碼都能夠避免的。
結束
- 由於自己才疏學淺,難免會有紕漏,假如你發現了錯誤的地方,還望留言給我指出來,我會對其加以修正。
- 如果你覺得文章還不錯,你的轉發、分享、贊賞、點贊、留言就是對我最大的鼓勵。
- 感謝您的閱讀,十分歡迎並感謝您的關注。