记录日常工作中一些容易被忽视的错误及细节,持续更新......

一、问题:HashMap<Long, String>中,用get(Integer key)取不到值

        Map<Long, String> map = new HashMap<Long, String>();
map.put(1L, "1");
System.err.println(map.get(1));// null
System.err.println(map.get(1L));//

1.首先想到Long与Integer的hashCode方法不同,Integer-value   Long-(int)(value ^ (value >>> 32))

但是!!计算出的hashCode值是相同的,不是问题所在

2.查看HashMap源码:注意加亮部分

  先比较key.hash,然后first.key == key || key.equals(first.key)

     /**
* 先比较key.hash,然后first.key == key || key.equals(first.key)
*/
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}

先看first.key == key:"=="比较地址值,l是Long cache[]中的1,o是Integer cache[]中的1,false

        Long l = 1L;
Object o = 1;
System.err.println(l == o);// false // 反编译后:
Long l = Long.valueOf(1L);
Object o = Integer.valueOf(1);
System.err.println(l == o);

然后看key.equals(first.key):先检查类型,false

        //Long的equals方法
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}

引发新的问题:为什么这个是true?——反编译解决

        Long l = 1L;
System.err.println(l == 1);// true // 反编译后:
Long l = Long.valueOf(1L);
System.err.println(l.longValue() == 1L);//编译器直接将1转成1L

二、两个值相等的Integer不“==”

        Integer c = 99999;
Integer d = 99999;
System.out.println(c == d);// false

Integer c = 99999;// 反编译:Integer c = Integer.valueOf(99999);

查看Integer源码:

-128 <= i <= 127时,直接在Integer cache[]中取;否则,new Integer(i)

        public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

结论:

        int a = 99999;
int b = 99999;
System.err.println(a == b);// true Integer c = 99999;
Integer d = 99999;
System.out.println(c == d);// false Integer e = 127;
Integer f = 127;
System.out.println(e == f);// true

三、List.remove()方法调用错误

注意list两个remove方法,remove(int index)  remove(Object o)

    public static void main(String[] args) {
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < 9999999; i++) {
list.add(i);
} // remove(int index)
long before = System.currentTimeMillis();
int i = 8888888;
list.remove(i);
long after = System.currentTimeMillis();
System.err.println("index=" + (after - before));// 6ms // remove(Object o)
long before = System.currentTimeMillis();
Integer i = 8888888;
list.remove(i);
long after = System.currentTimeMillis();
System.err.println("Object=" + (after - before));// 96ms }

四、三目运算符与自动拆装箱

        Map<String,Boolean> map = new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : false);// Exception in thread "main" java.lang.NullPointerException

查问题:

  NullPointerException找不出原因

  反编译看: ((Boolean)map.get("test")) == null

        HashMap map = new HashMap();
Boolean boolean1 = Boolean.valueOf(map == null ? false : ((Boolean)map.get("test")).booleanValue());

结论:

  三目运算符的语法规范,参见 jls-15.25

  三目运算符 当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。

以后注意:

1、保证三目运算符的第二第三位操作数都为对象类型

        Map<String,Boolean> map =  new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : Boolean.FALSE);

2、自动拆装箱问题

        Integer integer = 1; // 装箱  Integer integer=Integer.valueOf(1); new Integer()
int i = integer; // 拆箱 int i=integer.intValue();

1)包装对象的数值比较,不能简单的使用==(只有-128到127之间IntegerCache内的数字可以,但是这个范围之外还是需要使用equals比较)。

2)自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。

3)如果一个for循环中有大量装箱操作,会浪费很多资源。

五、switch语句忘记break

本来我跟你现在想的一样,一定不会忘,直到遇到了这个问题。

        int i = 3;
switch (i) {
case 1:
System.out.println(1);
break;
case 2:
System.out.println(2);
break;
case 3:
System.out.println(3);
// 没有break, 不会有问题
}

当你需要在之后接着case的时候,直接复制case 3,就bug了。

(1)case完一定break,除非特别需要穿透到下一个case;

(2)复制代码前后都要检查是否有问题。

六、数值溢出问题

    // 为了更好的展示问题,代码举出的是较极端的情况
public void overFlow(int a) {
int b = 999999 * a; // 6个9 int最大值=2147483647
int limit = 999999999; // 9个9
if (b < limit) {
System.out.println("a*b小于limit");
}
}

如果a传入一个较大的int值,a*999999之后会超过int的最大值

而默认结果是int类型,会将a*999999的结果强转成int,导致不是想要的结果的结果

即使a*999999是大于limit的,强转成int后,b可能会比limit小,甚至可能是负数

解决:

    // 用long类型计算(还会用一定风险)
public void overFlow(int a) {
long b = 999999L * a;
int limit = 999999999;
if (b < limit) {
System.out.println("a*999999小于limit");
}
} // 将加法和乘法转变成减法和除法运算
public void overFlow(int a) {
int limit = 999999999;
if (a < limit/999999) {
System.out.println("a*999999小于limit");
}
}

七、对象引用问题

public static void main(String[] args) {
Map<Integer, Inner> map = new HashMap<Integer, Inner>(); // inner1.list [1]
Inner inner1 = new Inner(new LinkedList<Integer>());
inner1.getList().add(1);
map.put(1, inner1); // inner2.list [1, 2]
Inner inner2 = new Inner(map.get(1).getList());
inner2.getList().add(2);
map.put(2, inner2); for (Entry<Integer, Inner> entry : map.entrySet()) {
System.err.println("" + entry.getKey() + " " + entry.getValue().getList());
} /**
* 目的:inner1.list [1] inner2.list [1, 2]
* 结果:inner1.list [1, 2] inner2.list [1, 2]
*/
} static class Inner {
List<Integer> list; public List<Integer> getList() {
return list;
} public Inner(List<Integer> list) {
this.list = list;
}
}

分析:

1.将inner1.list的引用给了inner2.list,nner1.list inner2.list指向的是同一个List。

2.很简单的问题,开发时习惯了构造方法里这样写:this.list = list;

解决:

this.list = list;  改成   this.list = new LinkedList<Integer>(list);

Java日常错误及需要注意细节,持续更新......的更多相关文章

  1. java 学习必备的软件,持续更新中

    小编会持续更新在学习Java过程中需要的软件以及各种文件: 话不多说,看行动! 一:JDK (1)JDK1.8(*64): 链接:https://pan.baidu.com/s/1vM0jNXn2CT ...

  2. Java中的static(1)【持续更新】——关于Eclipse的No enclosing instance of type ... 错误的理解和改正

    No enclosing instance of type SomeClass is accessible. Must qualify the allocation with an enclosing ...

  3. java 超详细面经整理(持续更新)2019.12.19

    目录 Java SE 请你解释HashMap中为什么重写equals还要重写hashcode? 请你介绍一下map的分类和常见的情况 请你讲讲Java里面的final关键字是怎么用的? 请你谈谈关于S ...

  4. java 超详细面经整理(持续更新)2019.12.18

    目录 Java SE 请你谈谈Java中是如何支持正则表达式操作的? 请你简单描述一下正则表达式及其用途. 请你比较一下Java和JavaSciprt? 在Java中如何跳出当前的多重嵌套循环? 讲讲 ...

  5. JAVA常见面试题问题简述(持续更新中)

    JAVA常见面试题问题简述 1. springcloud和dubbo的区别 ①相比之下springcloud 的社区会更加活跃,解决问题的速度也会越来越快,dubbo相对来说如果碰到没有解决的问题,就 ...

  6. Myeclipse中web project各种常见错误及解决方法(持续更新)

    创建web project时的问题 error:Install Dynamic web Module Facet卡住 solution:把网络关掉再创建就可以 Servlet error:The se ...

  7. 【java学习】实践中总结--持续更新中

    目录: 一些定义 配置环境 相关语法 1.一些定义 java中DO的含义: https://blog.csdn.net/canot/article/details/51698047 DAO 中包含了各 ...

  8. 【java】Java相关学习参考链接(持续更新)

    How to do in java,https://howtodoinjava.com/,Java手册,分版本,并且有每个版本的新特性的详细解析. Java World,https://www.jav ...

  9. java常用代码段整理(持续更新)

    FileWriter指定编码格式 FileWriter 默认是用(ISO-8859-1 or US-ASCII)西方编码的,总之不是UTF-8的,而FileWriter类有getEncoding方法, ...

随机推荐

  1. leetcode之 两数之和

    # -*- coding: utf-8 -*- # @Time : 2018/9/27 21:41 # @Author : cxa # @File : twonum.py # @Software: P ...

  2. 实现checkebox全选取消操作

    方法一: javascript代码: function checkedChild(obj,index){ var checkBoxs = document.getElementsByName(&quo ...

  3. Android浮动窗口的实现

    1.浮动窗口的实现原理 看到上图的那个小Android图标了吧,它不会被其他组建遮挡,也可以响应用户的点击和拖动事件,它的显示和消失由WindowManager直接管理,它就是Android浮动窗口. ...

  4. 在JAVA中记录日志的十个小建议

    JAVA日志管理既是一门科学,又是一门艺术.科学的部分是指了解写日志的工具以及其API,而选择日志的格式,消息的格式,日志记录的内容,哪种消息对应于哪一种日志级别,则完全是基于经验.从过去的实践证明, ...

  5. MySQL学习笔记:创建整年日期

    见识到另外一种创意,惊讶! 1.创建小数据表 0-9 # 创建小数据表 DROP TABLE IF EXISTS aa_numbers_small; CREATE TABLE aa_numbers_s ...

  6. Fix Valgrind's must-be-redirected error in Gentoo

    Last week, I tried to use Valgrind to identify potential memory related bugs, since segmentation fau ...

  7. SourceTree 3.0.17如何跳过注册进行安装? — git图形化工具(一)

    SourceTree 3.0.17个人版本的尝试跳过注册方式好几次都没成功,于是下载了企业版本https://www.sourcetreeapp.com/enterprise. 安装过程: 1.首次点 ...

  8. poj 2187 N个点中输出2点的最大距离的平方

    旋转卡壳 Sample Input 40 00 11 11 0Sample Output 2 # include <iostream> # include <cstdio> # ...

  9. apache camel 条件路由

    <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route id="e ...

  10. Java学习(异常类)

    一.什么是异常: 异常就是在运行时产生的问题.通常用Exception描述. 在java中,把异常封装成了一个类,当出现问题时,就会创建异常类对象并抛出异常相关的信息(如详细信息,名称以及异常所处的位 ...