背景
最近同事寫的程序報了一個非常神奇的錯,錯誤信息如下:
Error:(6, 28) java: 非法字符: 'uff0c'
Error:(6, 19) java: 不是語句
Error:(7, 15) java: 需要';'
喊我一起去解決這個問題,看到這個錯誤的時候,我首先去搜"uff0c"這個字符串,居然沒有搜到,然後查看的報錯的代碼位置,發現也是正常的,代碼如下:
Long id = subjectOption.getId();
// u000d 如果id爲空則新增,否則爲修改
if (id == null) {
s = new SubjectOption();
s.setQuestionnaireCode(subjectInfoDTO.getQuestionnaireCode());
s.setSubjectCode(subjectInfoDTO.getCode());
s.setTypeCode(subjectInfoDTO.getTypeCode());
s.setName(subjectOption.getName());
s.setValue(subjectOption.getValue());
s.setSort(subjectOption.getSort());
subjectOptionMapper.insertSubjectOption(s);
} else {
subjectOption.setTypeCode(subjectInfoDTO.getTypeCode());
subjectOptionMapper.updateSubjectOption(subjectOption);
}
看上去這是一個很正常的代碼,沒有任何問題,但是報錯位置在這裏,經過我逐行的排查,發現問題出現在第二行的註釋上面,刪掉這行代碼就會沒有任何問題出現,難道是註釋裏面的代碼被執行了嗎?
經過我上網查詢了相關資料,發現原因是Unicode解碼發生在任何詞彙解碼之前。而 \u000d 是一個換行符,因此對註釋進行了終止導致換行符後面的註釋代碼被執行了。爲了證明這一點,我寫了個Demo,代碼如下:
public class Test {
public static void main(String[] args) {
String str = "字符串1";
// u000d str="Hello World!";
System.out.println(str);
}
}
執行後結果爲:Hello World!
上面的代碼等效於下面的代碼:
public class Test {
public static void main(String[] args) {
String str = "字符串1";
//
str="Hello World!";
System.out.println(str);
}
}
上面問題引申出一個概念“Unicode 逃逸”
那麼什麼叫Unicode 逃逸
我去 oracle 官網查看了一下 Java 語言規範(JLS 3)相關的解釋,大意如下:Unicode 轉義用於表示僅包含 ASCII 字符的 Unicode 符號。當您需要插入無法在源文件的字符集中表示的字符時,它將派上用場。JLS 3.3節的相關說明,Unicode 轉義包含一個反斜槓字符(\),後跟一個或多個'u'字符和四個十六進制數字。
因此,例子中的 \u000d將被視爲換行符。
爲什麼會有這種機制,有什麼作用
這種機制的好處在於它可以在 ASCII 和任何其他編碼之間來回切換,並且不需要你弄清楚註釋的開始和結束位置!
總結
這種方式體現了Java核心的思想 —— 平臺一致性。
雖然這種處理方式看似很好,其實,它卻帶來了副作用(干擾語義),尤其是在文章或者評論中,我們一定要注意這樣的“特殊字符”帶來的Bug。
原創聲明:本文爲【Java學習提升】原創博文,轉載請註明出處。
本文來源於公衆號:【Java學習提升】 專注於Java領域技術分享,Java知識體系學習、分享面試經驗,讓我們結伴而行,共同成長!