首页 文章

从BigDecimal中删除十进制结束零

提问于
浏览
2

我写测试并希望将BigDecimal结果与期望值进行比较 . 我想使用方法 Assert.assertEquals(BigDecimal, BigDecimal) 因为如果drop它显示精确的比较值,并且在eclipse中我可以显示比较窗口 .

所以在代码中我有方法返回BigDecimal舍入到2位小数 . 在测试用例中,我现在返回的数字没有非零十进制数字 . 所以我想创建具有标度0的BigDecimal并且修剪返回BigDecimal到相同的比例 .

为了更复杂,我现在有方法 getDecimal(Object [,Optionaly int scale]) ,它从任何具有正确 toString() 值的对象创建BigDecimal,默认比例为99.我在主"heavy"代码中使用它,所以这个方法必须非常快(不需要创建另一个对象,不要使用regexp等 . ) .

这么简单的问题是:如何修改BigDecimal实例以通过最小负载修剪结束的十进制零 .

想要这样的srip

0.010 -> 0.01
5.000 -> 5
100 -> 100   not 1E+2

RESP:

someTrim(new BigDecimal("100.00")).equals(new BigDecimal(100))

做数学的事情

100.00 / (2, 99, DOWN) * 50.00 -> 2500

我的代码看起来像

public static BigDecimal getDecimal( Object value ) {
    // null here probably work beter, but dont want number longer then 99 decimal digits
    return getDecimal( value, 99 );
}

public static BigDecimal getDecimal( Object value, Integer scale ) {
    if ( value == null )
        return null;

    BigDecimal result = ( value instanceof BigDecimal ) ? ( BigDecimal ) value : new BigDecimal( value.toString() );

    if ( scale == null )
        return result;

    return result.setScale( scale, DOWN );
}

// Main heavy method could call this 100 000 times per tenant (cca 1500 tenants), of course not expect all in same time, but can severals
public static myModify(E entity){
    return myModify( entity.getValue(), entity.getDivisor(), entity.getMultiplicator() );
}

public static myModify( BigDecimal value, Integer divisor, BigDecimal multiplicator){
     return value.divide( getDecimal(divisor), 99, RoundingMode.DOWN ).multiply( multiplicator );
}

@Test
public void myModifyTest(){
    // Constructor have param: value, divisor, multiplicator
    E entity = new E(new BigDecimal("100.00"), 2, new BigDecimal("50.00"));
    // Should pass
    Assert.assertEquals(getDecimal(100), entity);
    // Should drop: java.lang.AssertionError: expected:<50> but was:<100>
    Assert.assertEquals(getDecimal(50), entity);
    // Not want: java.lang.AssertionError: expected:<5E+1> but was:<1E+2>
}

也许存在另一个删除相同错误的junit comparsion方法,但我不知道

感谢帮助 . 帕维尔

3 回答

  • 1

    official junit solution对此要求是使用hamcrest .

    使用java-hamcrest 2.0.0.0,我们可以使用以下语法:

    BigDecimal a = new BigDecimal("100")
        BigDecimal b = new BigDecimal("100.00")
        assertThat(a,  Matchers.comparesEqualTo(b));
    

    Hamcrest 1.3 Quick Reference

  • 0

    可能的方法:

    将BigDecimalToCompare实现为BigDecimal的包装类:

    public class BigDecimalToCompare {
    private final BigDecimal bigDecimal;
    
    public BigDecimal getBigDecimal(){
        return bigDecimal;
    }
    
    BigDecimalToCompare(BigDecimal bigDecimal){
        this.bigDecimal = bigDecimal;
    }
    
    @Override
    public boolean equals(Object obj){
        return bigDecimal.compareTo(((BigDecimalToCompare)obj).getBigDecimal()) ==0;
    }
    
    @Override
    public String toString(){
       return bigDecimal.toString();
    }
    
    public static BigDecimalToCompare of(BigDecimal bd){
        return new BigDecimalToCompare(bd);
    }
    

    }

    测试如下:

    @Test
    public void test(){
        BigDecimal a = new BigDecimal("100");
        BigDecimal b = new BigDecimal("100.00");
        assertEquals(BigDecimalToCompare.of(a),BigDecimalToCompare.of(b));
    }
    

    另一种可能的方案

    assertEquals(new BigDecimal("150").stripTrailingZeros(),
                    otherBigDecimal.stripTrailingZeros());
    
  • 0

    我可能找到了解决方案 . 创建另外两个BigDecimal实例是不好的,但不知道另一个侵入性较小的方法 . 如果没有必要,我做一点优化就不创建实例 .

    /** 
     * For text comparsion or log propouse
     * @return human readable text without decimal zeros 
     */
    public static String getPlainText( BigDecimal value ) {
        if ( value == null )
            return null;
    
        // Strip only values with decimal digits
        BigDecimal striped = ( value.scale() > 0 ) ? value.stripTrailingZeros() : value;
        return striped.toPlainString();
    }
    
    /** 
     * For comparison by equals method like test assertEquals
     * @return new instance without decimal zeros 
     */
    public static BigDecimal stripDecimalZeros( BigDecimal value ) {
        if ( value == null )
            return null;
    
        // Strip only values with decimal digits
        BigDecimal striped = ( value.scale() > 0 ) ? value.stripTrailingZeros() : value;
        // Unscale only values with ten exponent
        return ( striped.scale() < 0 ) ? striped.setScale( 0 ) : striped;
    }
    

    感谢@frhack . 可以写为测试你自己的Macther类类似于OrderingComparsion . 简单的等于

    public static class BigDecimalEqualComparator extends TypeSafeMatcher<BigDecimal> {
    
        private final BigDecimal expected;
    
        private static final String[] comparisonDescriptions = { "less than", "equal to", "greater than" };
    
        public BigDecimalEqualComparator( BigDecimal expected ) {
            this.expected = expected;
        }
    
        @Override
        public boolean matchesSafely( BigDecimal actual ) {
            return actual.compareTo( expected ) == 0;
        }
    
        // You must change this
        @Override
        public void describeMismatchSafely( BigDecimal actual, Description mismatchDescription ) {
            mismatchDescription.appendValue( actual.stripTrailingZeros().toPlainString() ).appendText( " was " )
                .appendText( asText( actual.compareTo( expected ) ) ).appendText( " " )
                .appendValue( expected.stripTrailingZeros().toPlainString() );
        }
    
        @Override
        public void describeTo( Description description ) {
            description.appendText( "a value equal to " ).appendValue( expected.stripTrailingZeros().toPlainString() );
        }
    
        private static String asText( int comparison ) {
            return comparisonDescriptions[signum( comparison ) + 1];
        }
    }
    

相关问题