谁是代码界3%的王者

      最近《Java开发手册(华山版)》推出了,几道易错的问题也随之而来,据说全部答对的人只有2.8%,接下来分析一下这几道题目。(题目来自阿里技术)

1.

public class FloatPrimitiveTest {	
    public static void main(String[] args) {	
        float a = 1.0f - 0.9f;	
        float b = 0.9f - 0.8f;	
        if (a == b) {	
            System.out.println("true");	
        } else {	
            System.out.println("false");	
        }	
    }	
}

这题是与浮点数相关的。先来谈谈浮点数,float与int都是4个字节32位的,那为什么float的表示范围会比int大的多呢?

首先int的有效位是31位,一位表示符号位,float的有效位比int少,但是其中的位数分为符号位,指数与有效数字,采用类似数学上的科学计数法来表示。所以范围会更大。

(图片截取自《码出高效》)

这是单精度浮点数float的存储格式.

由于计算机的存储是基于二进制的,所以有些小数是无法被准确存储的,(就像1/3在十进制中的表示一样0.333333......)因为除不尽,出现循环,但是计算机中数据类型的存储单元大小是有限的,所以当超过表示的位数时,就会把多余的给截断,造成精度丢失,所以以上题目选择false.

2.

public class FloatWrapperTest {	
    public static void main(String[] args) {	
        Float a = Float.valueOf(1.0f - 0.9f);	
        Float b = Float.valueOf(0.9f - 0.8f);	
        if (a.equals(b)) {	
            System.out.println("true");	
        } else {	
            System.out.println("false");	
        }	
    }	
}

此题还是涉及数据类型,只不过是包装类型。其实是换汤不换药,我们可以看看JDK中Float的valueOf()这个方法的实现

可以知道valueOf传入的参数是基本类型float类型,传入的参数本身就会出现精度缺失,自然在包装类的比较中还是会出现问题的。

以上两个问题的解决在开发手册中给予解决方案

3.

public class BigDecimalTest {	
    public static void main(String[] args) {	
        BigDecimal a = new BigDecimal(0.1);	
        System.out.println(a);	
        BigDecimal b = new BigDecimal("0.1");	
        System.out.println(b);	
    }	
}

以上代码的两种赋值方式一样吗?推荐第一种还是第二种?

经过运行可知第一种赋值方式出现了误差。

BigDecimal a = new BigDecimal(0.1);这种赋值方式,传入的数据类型是double,而double也是会出现float那样的精度丢失问题,所以在传入参数的这一环节已经发生了精度丢失。

BigDecimal a = new BigDecimal(“0.1”);这种赋值方式,传入的数据类型是String,而String的底层是用char[]来存储的,不会出现丢失问题。综上:还是要推荐用字符串类型进行构造。

4.

public class SwitchTest {	
    public static void main(String[] args) {	
        String param = null;	
        switch (param) {	
            case "null":	
                System.out.println("null");	
                break;	
            default:	
                System.out.println("default");	
        }	
    }	
}

这道题涉及的switch语句,运行时候是出现了异常。为什么呢?源码中的switch(param)调用了String的hashCode方法,switch方法只支持int类型的匹配,其他的数据类型都是被语法糖转化微整型来做判断与匹配的。

5.

public class LockTest {	
    private final static Lock lock = new ReentrantLock();	
	
    public static void main(String[] args) {	
        try {	
            lock.tryLock();	
        } catch (Exception e) {	
            e.printStackTrace();	
        } finally {	
            lock.unlock();	
        }	
    }	
}

下列哪种说法是错误的:

A: lock是非公平锁
B: finally代码块不会抛出异常
C: tryLock获取锁失败则直接往下执行

正确的答案是B,其实finally中是会抛出异常的,可能会由于对没加锁的对象进行解锁。

以上代码的lock是非公平锁。

这是ReenttrantLock的两个构造方法,在无参构造方法中,默认是创建非公平锁。

发布了29 篇原创文章 · 获赞 34 · 访问量 8153

猜你喜欢

转载自blog.csdn.net/weixin_39634532/article/details/94148483