文档章节

JDK的3个bug

孤独的探索号
 孤独的探索号
发布于 12/04 09:52
字数 828
阅读 1985
收藏 11

1.Annotation引用非空enum数组返回空数组

首次发现时的环境:JDK 1.8

首次发现所在项目:APIJSON

测试用例:

public enum RequestRole {

	/**未登录,不明身份的用户
	 */
	UNKNOWN,

	/**已登录的用户
	 */
	LOGIN,

	/**联系人,必须已登录
	 */
	CONTACT,

	/**圈子成员(CONTACT + OWNER),必须已登录
	 */
	CIRCLE,

	/**拥有者,必须已登录
	 */
	OWNER,

	/**管理员,必须已登录
	 */
	ADMIN;

	//似乎不管怎么做,外部引用后都是空值。并且如果在注解内的位置不是最前的,还会导致被注解的类在其它类中import报错。
	//虽然直接打印显示正常,但被@MethodAccess内RequestRole[] GET()等方法引用后获取的是空值
	public static final RequestRole[] ALL = {RequestRole.UNKNOWN};//values();//所有
	public static final RequestRole[] HIGHS;//高级
	static {
		HIGHS = new RequestRole[] {OWNER, ADMIN};
	}

	public static final String[] NAMES = {
			UNKNOWN.name(), LOGIN.name(), CONTACT.name(), CIRCLE.name(), OWNER.name(), ADMIN.name()
	};


}


@MethodAccess(
		GETS = RequestRole.ALL,
		HEADS = RequestRole.HIGHS
		)
public class Verify {

}


public class DemoVerifier {
	// <TableName, <METHOD, allowRoles>>
	// <User, <GET, [OWNER, ADMIN]>>
    public static final Map<String, Map<RequestMethod, RequestRole[]>> ACCESS_MAP;
	static { //注册权限
        ACCESS_MAP = new HashMap<String, Map<RequestMethod, RequestRole[]>>();
		ACCESS_MAP.put(Verify.class.getSimpleName(), getAccessMap(Verify.class.getAnnotation(MethodAccess.class)));
	}

	public static HashMap<RequestMethod, RequestRole[]> getAccessMap(MethodAccess access) {
		if (access == null) {
			return null;
		}

		HashMap<RequestMethod, RequestRole[]> map = new HashMap<>();
		map.put(GET, access.GET());
		map.put(HEAD, access.HEAD());
		map.put(GETS, access.GETS());
		map.put(HEADS, access.HEADS());
		map.put(POST, access.POST());
		map.put(PUT, access.PUT());
		map.put(DELETE, access.DELETE());

		return map;
	}

}

解决方案:

不抽象数组常量ALL,HIGHTS等,而是在每个用到的地方硬编码写死具体的值。

 

2.ArrayList可通过构造函数传入非指定泛型的List并在get时出错

首次发现时的环境:JDK 1.7

首次发现所在项目:APIJSON

测试用例:

JSONArray arr = new JSONArray(); //com.alibaba.fastjson.JSONArray
arr.add("s");

List<Long> list = new ArrayList<>(arr); 
list.get(0); //Exception cannot cast String to Long

解决方案:

1.改用 Open JDK8

2.升级 JDK

注:后面多次测试,已无法复现。

 

3.基本类型在三元表达式内可赋值为null,编译通过但运行出错

首次发现时的环境: JDK 1.7

测试用例:

int i = true ? null : 0; //Exception in thread "main" java.lang.NullPointerException

首次发现所在项目:ZBLibrary

解决方案:

在给基础类型用3元表达式赋值时,null 先转为基础类型的默认值。

 

最后再提2个不是bug,但容易引发编程bug的问题:

1.局部变量和同名的全局变量能在一个方法内,编译通过,运行也正常。

    public class Test {
        
        int val;
        @Override
        public String toString() {
            val = 1;
            String val = "";
            return super.toString();
        }
    }

如果两个变量中间隔了比较长的其它代码,很可能会导致开发人员将两者混淆,导致逻辑认知错误,从而写出或改出有问题的代码。

解决方案:

命名局部变量前先搜素,确保没有已声明的同名全局变量。

 

2. (非 JDK bug)Gson 通过 TypeToken 转换 List<T> 能写入不属于 T 类型的数据,get 出来赋值给 T 类型的变量/常量报错。


        String json = "[1, '2', 'a']";
        Type type = new TypeToken<Integer>(){}.getType();
        Gson gson = new Gson();
        List<Integer> list = gson.fromJson(json, type);
        
        Integer i = list == null || list.isEmpty() ? null : list.get(1); //Exception cannot cast String to Integer

解决方案:

1.手动检查列表内数据都符合泛型 T

2.改用 fastjson 等其它能静态检查类型的库。 

© 著作权归作者所有

共有 人打赏支持
孤独的探索号

孤独的探索号

粉丝 118
博文 22
码字总数 29359
作品 4
深圳
私信 提问
加载中

评论(13)

f
freezingsky
运气好,从来没遇到过!按规范书写代码,很重要
whaon
whaon
第一个RequestRole.ALL,外部不能访问?
开源中国首席一失足成千古风流人物以稀为贵
开源中国首席一失足成千古风流人物以稀为贵
1.泛型擦除 还需要自己研究下
2. 基本数据类型的引用类型 自动装箱拆箱也需要好好学习一下.
RyuuKazu
RyuuKazu

引用来自“xiaoaiwhc1”的评论

三元表达式那个应该也不算是bug吧?编译期不能确定具体的值,等运行时才动态指定,那时候报错也没有什么问题。如果能在编译期就检查各个表达式的返回类型就好了。

引用来自“孤独的探索号”的评论

算,如果是
int num = response == null ? 0 : response.getInteger("num");
这个编译不报错能理解,毕竟getInteger返回值只能在运行时确定,
但如果硬编码就是null
int num = response == null ? null : response.getInteger("num");
就应该编译报错,避免开发者一时手误/眼误写错,或者需求改了后改代码不小心把 Integer num 改成 int num 等导致bug。

引用来自“xiaoaiwhc1”的评论

试了一下, 确实应该算bug.
int i = x > y ? null : 123; 编译器通过, 运行报错.
int i = x > y ? null : "123"; 编译器直接报错.
int i = x > y ? null : null; 编译器直接报错.
至少, 这里编译器出现行为不一致的情况了. 当然, 不了解源码, 不知道为啥.
int i = x > y ? null : 123这条,如果开发者的预期是if(x<=y){i=123}else{throw new Exception()}呢?这条并不是运行时总报错的,只是运行时有可能报错。下面那两条是无论什么情况都会报错的。
xiaoaiwhc1
xiaoaiwhc1

引用来自“xiaoaiwhc1”的评论

三元表达式那个应该也不算是bug吧?编译期不能确定具体的值,等运行时才动态指定,那时候报错也没有什么问题。如果能在编译期就检查各个表达式的返回类型就好了。

引用来自“孤独的探索号”的评论

算,如果是
int num = response == null ? 0 : response.getInteger("num");
这个编译不报错能理解,毕竟getInteger返回值只能在运行时确定,
但如果硬编码就是null
int num = response == null ? null : response.getInteger("num");
就应该编译报错,避免开发者一时手误/眼误写错,或者需求改了后改代码不小心把 Integer num 改成 int num 等导致bug。
试了一下, 确实应该算bug.
int i = x > y ? null : 123; 编译器通过, 运行报错.
int i = x > y ? null : "123"; 编译器直接报错.
int i = x > y ? null : null; 编译器直接报错.
至少, 这里编译器出现行为不一致的情况了. 当然, 不了解源码, 不知道为啥.
妹子楼顶有鸽子
妹子楼顶有鸽子

引用来自“guor”的评论

只能算错误的调用,并不是bug

引用来自“孤独的探索号”的评论

问题是并没有看到源码或文档里说明不能这样做,如果有麻烦告诉我哦。
另外能编译时解决的问题最好不要留到运行时,否则和动态语言比就少了一个很大的优势了。

引用来自“guor”的评论

我觉得并不是这样的,就好比 long a = Long.valueOf("a"); 按照你的逻辑,这种也是bug?既然给了异常,就说明你的调用是错的,如果编译能解决所有问题,那还要测试做什么?
所谓bug,是实际输出与理论不一致
你这上面列的,都是理论就是错误,实际还是报错,哪是bug

引用来自“孤独的探索号”的评论

这个当然不算,因为它不属于基本语法上的错误,Long.valueOf(String s) 这个如果要在编译时检查代价非常高,且收益并不大。

int i = 判断条件 ? null : 其它值
这是基本语法 三元表达式 里面就出现了不应该允许的值,应该和
int i = null
一样编译报错
int i = (判断条件 ? null : 其它值).intValue()。基础数据类型不能设置为null,所以编译器只需要验证null是不是可以转换为Integer,很显然是可以的。
Javap代码如下:

Code:
0: aconst_null
1: checkcast #2 // class java/lang/Integer
4: invokevirtual #3 // Method java/lang/Integer.intValue:()I
7: istore_1
8: return
田心双木
田心双木
经验问题,多看看书
孤独的探索号
孤独的探索号

引用来自“guor”的评论

只能算错误的调用,并不是bug

引用来自“孤独的探索号”的评论

问题是并没有看到源码或文档里说明不能这样做,如果有麻烦告诉我哦。
另外能编译时解决的问题最好不要留到运行时,否则和动态语言比就少了一个很大的优势了。

引用来自“guor”的评论

我觉得并不是这样的,就好比 long a = Long.valueOf("a"); 按照你的逻辑,这种也是bug?既然给了异常,就说明你的调用是错的,如果编译能解决所有问题,那还要测试做什么?
所谓bug,是实际输出与理论不一致
你这上面列的,都是理论就是错误,实际还是报错,哪是bug
这个当然不算,因为它不属于基本语法上的错误,Long.valueOf(String s) 这个如果要在编译时检查代价非常高,且收益并不大。

int i = 判断条件 ? null : 其它值
这是基本语法 三元表达式 里面就出现了不应该允许的值,应该和
int i = null
一样编译报错
guor
guor

引用来自“guor”的评论

只能算错误的调用,并不是bug

引用来自“孤独的探索号”的评论

问题是并没有看到源码或文档里说明不能这样做,如果有麻烦告诉我哦。
另外能编译时解决的问题最好不要留到运行时,否则和动态语言比就少了一个很大的优势了。
我觉得并不是这样的,就好比 long a = Long.valueOf("a"); 按照你的逻辑,这种也是bug?既然给了异常,就说明你的调用是错的,如果编译能解决所有问题,那还要测试做什么?
所谓bug,是实际输出与理论不一致
你这上面列的,都是理论就是错误,实际还是报错,哪是bug
孤独的探索号
孤独的探索号

引用来自“guor”的评论

只能算错误的调用,并不是bug
问题是并没有看到源码或文档里说明不能这样做,如果有麻烦告诉我哦。
另外能编译时解决的问题最好不要留到运行时,否则和动态语言比就少了一个很大的优势了。
JDK 11 已进入候选发布阶段,计划9月25日发布正式版

JDK 11 达成了新的里程碑:现已进入候选发布阶段。按照 JDK Release Process(JEP 3),jdk/jdk11 稳定仓库目前对于 P1 错误修复是开放的。此外, JDK 11 将于9月份正式发布。 JDK 11 的发布进...

达尔文
08/22
4.6K
32
java.lang.OutOfMemoryError:Out of swap space?

近期遇到一个JVM崩溃问题,JVM在运行不定时间后会崩溃,崩溃的时间没发现有什么规律,有可能是一两天,有可能是一个月,近半年大概发生了3次,在第三次发生的时候终于引起了楼主的关注,楼主...

晓叹星沉
2016/09/05
49
0
java.nio.BufferOverflowException

Bug ID: 6526175 Votes 0 Synopsis Compiler throws BufferOverflowException should say that it ran out of memory Category java:compiler Reported Against Release Fixed State Priorit......

付翔
2010/06/29
0
0
阿里开源组件 fastjson-1.1.42 发布

Fastjson 1.1.42 发布了,主要改进内容包括: 1. 修复parser在处理循环引用在某些特定场景下的bug; 2. 支持在Bean上通过JSONType配置DisableCircularReferenceDetect/BeanToArray特性; 3....

wenshao
2014/10/11
9.1K
11
JDK1.6中线程池更好了,有allowCoreThreadTimeOut

要做异步任务执行队列,具体需求如下: 1. 有个线程池用于执行任务 2. 有个有界队列,用于缓存未执行的任务 3. 没有任务执行时,我希望线程池中的线程停掉 这看似是个很正常的需求,但是用J...

赵建勇
2014/03/22
2.3K
0

没有更多内容

加载失败,请刷新页面

加载更多

slot分发内容

slot元素作为组件模板之中的内容分发插槽。这个元素自身将被替换。 有 name 特性的 slot 称为具名 slot。 有 slot 特性的内容将分发到名字相匹配的具名 slot。 内容分发就是指混合父组件的内...

Carbenson
8分钟前
1
0
python开发入门

1.执行python文件 # python ./demo.py 2.Python ImportError: No module named 'requests'异常 解决方法: # pip install requests;...

硅谷课堂
9分钟前
1
0
官宣,PyTorch 1.0 稳定版本现已推出

简评:快来一起快乐地学习吧。 随着 PyTorch 生态系统和社区继续为开发人员提供有趣的新项目和教育资源,今天(12 月 7日)在 NeurIPS 会议上发布了 PyTorch 1.0 稳定版。研究人员和工程师现...

极光推送
22分钟前
1
0
对比理解adr,ldr指令

很多人在写简单的裸机代码或分析uboot时,常常遇到adr ldr指令。却分不清这2者的区别,今天就来谈谈adr与ldr指令。 参照韦老师的代码和Makefile写了test_adr.S: .text .globl _start _start...

天王盖地虎626
33分钟前
2
0
将spring boot 项目注册为Linux的服务

springboot 注册为Linux系统服务 springboot 注册为Linux系统服务

miaojiangmin
34分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部