Java開發常犯的錯誤及基本知識(持續更新)


為什么lambda表達式無法聲明throws異常,而必須要在內部捕獲?

實際上這是跟重寫的方法有關,比如重寫Runnable的run方法,就必須在內部捕獲異常:

Runnable runnable =
        () -> {
          synchronized (objectWaitMainClass) {
            try {
              objectWaitMainClass.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        };

因為Runnablerun方法沒有聲明任何異常,所以實現了該方法的方法就無法聲明任何異常,只能內部捕獲

 

下面自定義一個接口,接口方法中聲明了異常

@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類中的replacereplaceAll方法底層也是用的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));

https://stackoverflow.com/questions/4819635/how-to-remove-all-null-elements-from-a-arraylist-or-string-array 

 

調用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://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485599&idx=1&sn=d83ff4e6b1ee951a0a33508a10980ea3&chksm=cea24754f9d5ce426d18b435a8c373ddc580c06c7d6a45cc51377361729c31c7301f1bbc3b78&token=1328169465&lang=zh_CN&scene=21#wechat_redirect

https://github.com/alibaba/p3c/blob/master/阿里巴巴Java開發手冊(華山版).pdf

https://stackoverflow.com/questions/10963775/cannot-reference-x-before-supertype-constructor-has-been-called-where-x-is-a


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM