背景
最近同事写的程序报了一个非常神奇的错,错误信息如下:
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知识体系学习、分享面试经验,让我们结伴而行,共同成长!