為什么lambda表達式無法聲明throws異常,而必須要在內部捕獲?
實際上這是跟重寫的方法有關,比如重寫Runnable的run方法,就必須在內部捕獲異常:
Runnable runnable = () -> { synchronized (objectWaitMainClass) { try { objectWaitMainClass.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } };
因為Runnable的run方法沒有聲明任何異常,所以實現了該方法的方法就無法聲明任何異常,只能內部捕獲;
下面自定義一個接口,接口方法中聲明了異常:
@FunctionalInterface public interface ThrowException { /** * 可能會拋出異常 * * @throws Exception */ public void throwException() throws Exception; }
用lambda表達式重寫:
ThrowException throwException = () -> { synchronized (objectWaitMainClass) { objectWaitMainClass.wait(); } };
就不用lambda內部捕獲,基類接口中已經聲明了該異常。
整個測試類:
/** * * * <ul> * <li>由於基類中的方法沒有聲明異常比如Runnable#run方法,所以重寫該run方法就不能聲明異常,比如要內部捕獲; * <li>如果基類中方法聲明了異常,那么重寫該方法就可以不再內部捕獲,比如本類中的內部接口中的方法{@link ThrowException#throwException()} * </ul> * * @see ThrowException#throwException() * @see Runnable#run() * @author rhyme * @date 2020/5/30 12:02 */ public class LambdaExceptionMain { public static void main(String[] args) throws InterruptedException { Class<LambdaExceptionMain> objectWaitMainClass = LambdaExceptionMain.class; Runnable runnable = () -> { synchronized (objectWaitMainClass) { try { objectWaitMainClass.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }; ThrowException throwException = () -> { synchronized (objectWaitMainClass) { objectWaitMainClass.wait(); } }; } /** * 自定義一個函數式接口,方法中聲明了異常 */ @FunctionalInterface public interface ThrowException { /** * 可能會<b>拋出異常</b>的函數式接口中的方法 * * @throws Exception */ public void throwException() throws Exception; }
CRLF,CR,LF的區別和聯系
windows系統文件格式默認換行"是\r\n",即CRLF;
UNIX/Linux系統文件格式默認換行是"\n",即LF;
MacOS系統文件格式默認換行由"\r",即CR。
所以比如在windows上,用Notepad++打開一個文件,想要匹配里面的換行,就要用"\r\n"匹配。
數據庫字段最好不要用基本類型
比如 一個字段設定為@Column(name = "PRIORITY", nullable = false) int priority;
雖然有注解檢查該字段不能為null,但是如果不給該字段傳值,該字段也不為null,因為它是基本類型int,默認值是0,就以0作為值賦給了字段priority,與期望不符合;
所以應該@Column(name = "PRIORITY", nullable = false) Integer priority;
這樣如果該字段為null,插入到數據庫時就會報該字段不能為null的錯誤!
自定義異常
領域模型命名規約
建議使用 try-with-resources 語句
https://github.com/RhymeXY/java-basic-demos/blob/master/common/src/main/java/com/xy/java/basic/demos/utils/InputFromSystemInUtil.java
Java 7 中引入了 try-with-resources 語句,該語句能保證將相關資源關閉,優於原來的 try-catch-finally 語句,並且使程序代碼更安全更簡潔。
反例
private void handle(String fileName) { BufferedReader reader = null; try { String line; reader = new BufferedReader(new FileReader(fileName)); while ((line = reader.readLine()) != null) { ... } } catch (Exception e) { ... } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { ... } } } }
正例:
private void handle(String fileName) { try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) { String line; while ((line = reader.readLine()) != null) { ... } } catch (Exception e) { ... } }
spring boot 多模塊開發時,依賴注入其他模塊的bean失敗
比如A模塊依賴B模塊,A需要自動注入B模塊的一個Bean,啟動時找不到B模塊的Bean依賴,極大的可能是A模塊啟動類所在的包和B模塊所在的包名不一樣,所以掃描不到B模塊,在A模塊的啟動類加上@ComponentScan注解掃描B模塊的包,如果需要B模塊的Bean需要配置文件,A模塊還需要配置。
被final修飾的變量
被final修飾的變量只能初始化一次,所以它的引用不能改變,引用的對象實例可以改變!
public class FinalObjectTest { @Test public void test(){ A a = new A(1); A temp = new A(9); final A finalA = a; a.setValue(2); System.out.println(finalA.value); // 2 System.out.println(a.value); // 2 // finalA = temp; 會報錯 // 被final修飾的變量只能初始化一次,所以它的引用不能改變,引用的對象實例可以改變! } @Data @AllArgsConstructor private class A { private int value; } }
Java interface
Java的接口interface,無父類,不是Object類的子類。
在Java里用正則表達式,注意性能
private static final Pattern pattern = Pattern.compile("^[A-Za-z\\u4e00-\\u9fa5][A-Za-z\\u4e00-\\u9fa50-9_\\-]{0,31}$");
Pattern.compile底層代碼方法會編譯一次正則表達式
Matcher matcher = pattern.matcher(內容)
pattern對象的matcher方法,如果沒有編譯,會編譯一次,上面Pattern.compile方法如果編譯了這里不會編譯;
注意!!!一定要保證一個正則表達式只編譯(初始化)一次。
再比如String類中的replace、replaceAll方法底層也是用的Pattern.compile,每調用一次replace*方法都會編譯一次,效率太低了,所以像上面一樣定義一個private static final Pattern pattern = Pattern.compile(regex),保證一個正則表達式值初始化一次,再利用matcher匹配字符串調用replace(String replacement)方法。
利用策略模式和工廠模式優化多個if-else
多個if-else通常邏輯看起來很復雜,不方便維護,用策略模式和工廠模式優化
https://www.cnblogs.com/theRhyme/p/10339382.html
Collection (如List、Set) 的 "All elements are null"的情況
一個Java集合的Size是1,雖然它!=null && size>0,但是它內容是"All elements are null",相當於它就是空的!
這時候通過集合類的removeAll方法移除這些值為"All elements are null"的屬性:
tourists.removeAll(Collections.singleton(null));
調用Set.addAll()方法時拋UnsupportedOperationException異常
上面的Set是Map中keySet的返回結果。
程序中這樣兩句代碼運行時,拋UnsupportedOperationException異常。
最初感覺很奇怪,Map.keySet()方法返回一個Set呀,Set明明是支持add()、addAll()方法的,怎么會拋“不支持操作”異常呢。
結果發現,問題不是出在Set上,而是出在Map的keySet()方法上。
下面是摘自API幫助文檔的說明
Map中的方法public Set keySet()返回此映射中所包含的鍵的 set 視圖。該集合受映射的支持,所以映射的變化也反映在該集合中,反之亦然。該集合支持元素的移除,通過 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作,從該映射中移除相應的映射關系。它不支持 add 或 addAll 操作。
相當於在Map.keySet()得到的集合中插入元素,故此時Set不再支持addAll()方法。
所以應該new一個Set,再使用addAll:
Array轉ArrayList
當需要把Array轉成ArrayList的時候,開發人員經常這樣做:
List<String> list = Arrays.asList(arr);
Arrays.asList()會返回一個ArrayList,但是要特別注意,這個ArrayList是Arrays類的靜態內部類,並不是java.util.ArrayList類。java.util.Arrays.ArrayList類實現了set(), get(),contains()方法,但是並沒有實現增加元素的方法(事實上是可以調用add方法,但是沒有具體實現,僅僅拋出UnsupportedOperationException異常),因此它的大小也是固定不變的。為了創建一個真正的java.util.ArrayList,你應該這樣做:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
ArrayList的構造方法可以接收一個Collection類型,而java.util.Arrays.ArrayList已經實現了該接口。
判斷一個數組是否包含某個值
開發人員經常這樣做:
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
以上代碼可以正常工作,但是沒有必要將其轉換成set集合,將一個List轉成Set需要額外的時間,其實我們可以簡單的使用如下方法即可:
Arrays.asList(arr).contains(targetValue);
或者
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
第一種方法可讀性更強。
RabbitMQ消費者拋異常未捕獲控制台日志持續打印問題
消費者接受消息,進行一系列處理,但是由於某些原因處理過程中該消費者的拋出了異常,並且不捕獲(直接 throws IOException 拋出去);
由於拋出了IOException,那么這條消息就會再次被發送到該隊列,消費者就再次收到,而消費者拋出異常,所以就形成了一個死循環(除非不再有類似IO的異常),那么控制台日志就一直打印該消費者的拋出異常。
解決方法:https://www.cnblogs.com/theRhyme/p/10758249.html
TimeUnit枚舉
TimeUnit是java.util.concurrent包下面的一個枚舉類,TimeUnit提供了可讀性更好的線程暫停操作。
在JDK5之前,一般我們暫停線程是這樣寫的:
Thread.sleep(2400000)//可讀性差
可讀性相當的差,一眼看去,不知道睡了多久;
在JDK5之后,我們可以這樣寫:
TimeUnit.SECONDS.sleep(4);
TimeUnit.MINUTES.sleep(4);
TimeUnit.HOURS.sleep(1);
TimeUnit.DAYS.sleep(1);
清晰明了;
另外,TimeUnit還提供了便捷方法用於把時間轉換成不同單位,例如,如果你想把秒轉換成毫秒,你可以使用下面代碼
TimeUnit.SECONDS.toMillis(44);// 44,000
Java訪問控制
Java中的private、默認、protected、public訪問控制。
這個老是忘記。
Java代碼優化
https://www.cnblogs.com/xrq730/p/4865416.html
參考來源:
https://blog.csdn.net/woyaoxuejavaya/article/details/52472508
https://www.cnblogs.com/chenpi/p/5508949.html#_label1
https://www.cnblogs.com/chenpi/p/5614290.html#_label9
https://www.cnblogs.com/theRhyme/p/10758249.html
https://zhidao.baidu.com/question/1510955557965485900.html
https://github.com/alibaba/p3c/blob/master/阿里巴巴Java開發手冊(華山版).pdf