首页 > 编程语言 >原来你是这样的JAVA--[07]聊聊Integer和BigDecimal

原来你是这样的JAVA--[07]聊聊Integer和BigDecimal

时间:2024-02-24 17:26:36浏览次数:18  
标签:JAVA 07 -- valueOf equals System println Integer BigDecimal

今天来聊聊Java中跟数值处理相关的两个类型Integer和BigDecimal。 说起这两个类型,我们肯定都不陌生,但是其中有些容易踩到的坑需要注意避让。

Integer

整型我们应该每天都会用到,但是每种语言还是有自己的特性。从敬姐刚从.NET转过来的时候踩过的一个坑说起:话说在.NET世界中,数值的基本类型和包装类型是会自动转换的,所以数值比较很自然地就会使用 a==b,但是到java这却行不通了,顿时一脸懵。

数值比较及自动装箱

    @Test
    public void Interger(){
        Integer x = 127;
        Integer y = 127;
        Integer m = 99999;
        Integer n = 99999;
        System.out.println("x == y: " + (x==y));
        System.out.println("m == n: " + (m==n));
        System.out.println("x.equals(y): " + x.equals(y));
        System.out.println("m.equals(n): " + m.equals(n));
        //执行结果
//        x == y: true
//        m == n: false
//        x.equals(y): true
//        m.equals(n): true
    }

仔细观察可以发现,==比较,较小的两个相同的Integer返回true,较大的两个相同的Integer返回false,这是为何呢?

一起看一下Integer类的源码,发现其中的IntegerCache类。这是Java为了节省空间、提升性能采取的优化机制,常量池的大小为一个字节(-128~127)。

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer[] cache;
        static Integer[] archivedCache;

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            // Load IntegerCache.archivedCache from archive, if possible
            CDS.initializeFromArchive(IntegerCache.class);
            int size = (high - low) + 1;

            // Use the archived cache if it exists and is large enough
            if (archivedCache == null || size > archivedCache.length) {
                Integer[] c = new Integer[size];
                int j = low;
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                archivedCache = c;
            }
            cache = archivedCache;
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

而对于valueOf(int i)方法,直接使用了常量池IntegerCache

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

所以当遇到 Integer x = 127; 时,会进行自动装箱,调用的是:

Integer x = Integer.valueOf(127);

为了节省内存,Integer.valueOf()对于较小的数,始终返回相同的实例,因此,比较“恰好”为true。但我们绝不能因为Java标准库的Integer内部有缓存优化就用比较,必须用equals()方法比较两个Integer。

创建实例

因为Integer.valueOf()可能始终返回同一个Integer实例,因此,在我们自己创建Integer的时候,以下两种方法:

方法1:Integer n = new Integer(100);
方法2:Integer n = Integer.valueOf(100);

方法2更好,因为方法1总是创建新的Integer实例,方法2把内部优化留给Integer的实现者去做,即使在当前版本没有优化,也有可能在下一个版本进行优化。
我们把能创建“新”对象的静态方法称为静态工厂方法。Integer.valueOf()就是静态工厂方法,它尽可能地返回缓存的实例以节省内存。简而言之:创建新对象时,优先选用静态工厂方法而不是new操作符。

上个看个有点特别的例子:

@Test
    public void instance() {
        //每次创建一个新实例
        Integer a1 = new Integer(100);
        Integer a2 = new Integer(100);
        Assert.assertFalse(a1 == a2);
        //add
        Integer a3 = new Integer(200);
        //注意这里喽!!
        Assert.assertTrue(a1 + a2 == 200);
        Assert.assertTrue(a1 + a2 == a3);
    }

因为+这个操作符不适用于 Integer 对象,首先 a1 和 a2 进行自动拆箱操作,进行数值相加,即a3 == 40。

BigDecimal

BigDecimal适合商业计算场景,用来对超过16位有效位的数进行精确的运算。

Double转换为BigDecimal

我们在使用BigDecimal时,为了防止精度丢失,推荐使用它的 BigDecimal(String) 构造方法来创建对象。

    @Test
    public void double2decimal() {
        Double d = 0.1d;
        System.out.println(new BigDecimal(d));//0.1000000000000000055511151231257827021181583404541015625
        System.out.println(new BigDecimal(d.toString()));//0.1
        System.out.println(BigDecimal.valueOf(d));//0.1
    }

保留几位小数

通过 setScale方法设置保留几位小数以及保留规则。

@Test
    public void decimalTest() {
        BigDecimal a = new BigDecimal("1.2345");
        System.out.println(a.toString());
        //BigDecimal保留几位小数
        BigDecimal b = a.setScale(3, RoundingMode.HALF_DOWN);
        System.out.println(b.toString());
    }

BigDecimal 值比较

BigDecimal的等值比较应该使用compareTo()方法,而不是equals()方法。

/**
     * BigDecimal等值比较
     * equals:既比较数值,又比较精度;
     * compareTo:仅比较数值
     */
    @Test
    public void compare() {
        BigDecimal a = BigDecimal.valueOf(1);
        BigDecimal b = BigDecimal.valueOf(1.00);
        Assert.assertFalse(a.equals(b));
        Assert.assertEquals(0, a.compareTo(b));
    }

调试一下BigDecimal的equals和compareTo方法,发现equals()方法会比较精度,但是compare()方法不会。


BigDecimal 除法

BigDecimal.divide(),除法运算注意要设置精度,否则在除不尽的情况下会抛异常。

    @Test
    public void divide(){
        BigDecimal a=BigDecimal.valueOf(1);
        BigDecimal b=BigDecimal.valueOf(3);
        //直接抛异常
//        System.out.println(a.divide(b));
        //正常返回 0.3333
        System.out.println(a.divide(b,4,RoundingMode.HALF_EVEN));
    }

代码示例

文示例代码参考:jing-yes-java (https://github.com/cathychen00/jing-yes-java/tree/master/jing-yes-j2se/src/test/java/com/jingyes/j2se/tests)

标签:JAVA,07,--,valueOf,equals,System,println,Integer,BigDecimal
From: https://www.cnblogs.com/janes/p/18031284

相关文章

  • NICA 校际交流赛#2 游记
    \(1\!:\!15\)到达考场,检测好网络和电脑。分配任务,sxshm打前\(5\)题,tcy01_QAQ_打\(6,\!7\)两题,我打后面的题。\(1\!:\!30\)显得无聊,关掉浏览器,准备闭目养神。结果桌面卡死了,只好重启QwQ。旁边的tcy01_QAQ_开始整活:#include<windows.h>usingnamespacestd;intma......
  • CF1832B Maximum Sum 题解
    【题目描述】给定一个长度为\(n\)的数列,其中每个元素互不相同,进行\(k\)次操作,每次可以选择删除序列中最小的两个数或最大的一个数。求操作后剩余数的和的最大值。【思路】我们构造一组数据:首先我们看到题目中的一句话:每次可以选择删除序列中最小的两个数或最大的一个数。......
  • Leetcode 42.接雨水
    题目朴素解法:对于每列分别向左右扫描查找左右最高的柱子,对于每一个柱子接的水,那么它能接的水=min(左右两边最高柱子)-当前柱子高度。遍历每列时间复杂度为O(n),每列再扫描O(n),总共O(N^2)。classSolution{public:inttrap(vector<int>&height){//O(n^2)还是超......
  • 暑期集训 Day7 —— 模拟赛复盘
    ${\color{Green}\mathrm{Problem\1:最优包含}}$发现是DP,于是开始设计状态:DP[i][j]表示前一个字符串匹配到位置i,后一个匹配到j的最少修改次数。然后转移挂了:if(S[i]==T[j]){ DP[i][j]=min(DP[i][j],DP[i-1][j-1]);}else{ DP[i][j]=min(DP[i][j],DP[i-1][j-1]+1......
  • linux跳转到文件指定行
    在日常编程过程中,我们经常需要在一个比较大的文件中定位到某一行进行修改或查看。在Linux系统中,有很多种方法可以实现这个操作,例如使用文本编辑器、grep命令等。本文将从多个角度分析如何在Linux中跳转到文件指定行。一、使用vim编辑器 vim是Linux系统中一个非常常用的文本编......
  • 暑期集训 Day5 —— 模拟赛复盘
    ${\color{Green}\mathrm{Problem\1:选数}}$签到题,一眼二分,但是打模板时死循环了:while(L<R){ intmid=(L+R)>>1; if(check(mid))L=mid; elseR=mid+1;}后来发现+1要写在check通过的地方,不然容易mid值永远不变。while(L<R){ intmid=(L+R)>>1; ......
  • 暑期集训 Day9 —— 模拟赛复盘
    ${\color{Green}\mathrm{Problem\1:大河的序列}}$巨思维...其实只需要输出序列max即可。死因:\({\tiny去你的}\)快速幂intFast_power(intbase,intpower,intmod){longlongres=1;while(power){if(power&1){res......
  • 左偏树
    左偏树是一种可并堆(一系列的堆),支持以下操作:删除一个堆的最值。查询一个堆的最值。新建一个堆,只包含一个元素。合并两个堆。这个复杂度是\(O(\log)\)的。左偏树是一颗二叉树。定义“外结点”为儿子数量不等于\(2\)的结点,定义每个结点的\(dist\)为该结点到最......
  • 暑期集训 Day10 —— 模拟赛复盘
    ${\color{Green}\mathrm{Problem\0:water}}$题如其名,可以用单调队列做,但是数据范围直接暴力枚举每一高度就行。最不会打错的,还是暴力,所以用暴力。${\color{White}\mathrm{}}$${\color{White}\mathrm{}}$${\color{White}\mathrm{}}$${\color{Green}\mathr......
  • 暑期集训 Day12 —— 模拟赛复盘
    ${\color{Green}\mathrm{Problem\1:Subarray}}$Map.${\color{Green}\mathrm{Problem\2:小z玩游戏}}$数学题YYDS。我的做法是:首先枚举x的所有二进制位,找里面的\(1\),由于y要比x小,于是我们可以把y的当前位变为\(0\),然后后面的位从全0到全1,用前缀和统......