Java 断言等于 int long float

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41242135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:14:47  来源:igfitidea点击:

assert equals int long float

javajunit

提问by Pavel Niedoba

Is there an elegant way to assert numbers are equal while ignoring their classes? I want to use it in JUnit tests framework but for example

有没有一种优雅的方法来断言数字相等而忽略它们的类?我想在 JUnit 测试框架中使用它,但例如

Assert.assertEquals(1,1L)

fails with java.lang.AssertionError: expected: java.lang.Integer<1> but was: java.lang.Long<1>

因 java.lang.AssertionError 失败:预期:java.lang.Integer<1> 但为:java.lang.Long<1>

I expect there is a nice method somewhere which compares only value and works with int, long, float, byte, double, BigDecimal, BigInteger, you name it...

我希望在某处有一个很好的方法,它只比较值并与 int、long、float、byte、double、BigDecimal、BigInteger 一起使用,您可以命名它...

采纳答案by Mena

One workaround with some overhead would be to wrap the values in BigDecimalobjects, as BigDecimalconstructor overloads take long, intand doubleprimitives.

一些开销的一种解决方法是将包裹中的值的BigDecimal对象,BigDecimal构造函数重载需要longintdouble原语。

Since new BigDecimal(1l).equals(new BigDecimal(1.0))holds true,

既然new BigDecimal(1l).equals(new BigDecimal(1.0))成立true

Assert.assertEquals(new BigDecimal(1.0), new BigDecimal(1l));  

should work for you.

应该为你工作。

Edit

编辑

As Hulkstates below, the scale of the BigDecimalobjects is used in the equalscomparison, but not in the compareTocomparison. While the scale is set to a default 0for the constructor taking long, it is inferred through some calculation in the constructor taking double. Therefore the safest way to compare values (i.e. in edge cases for doublevalues) mightbe through invoking compareToand checking the outcome is 0instead.

正如Hulk在下面所说的,BigDecimal对象的比例用于equals比较,但不用于compareTo比较。虽然比例设置0为构造函数的默认值long,但它是通过构造函数中的一些计算推断出来的double。因此,比较值的最安全方法(即在值的边缘情况下double可能是通过调用compareTo和检查结果来0代替。

回答by Roland

Wrap that functionality in your own Matcherand use it with assertThat.

将该功能包装在您自己的Matcher 中并将其与assertThat.

Sample matcher:

样本匹配器:

class IsAnyNumber extends BaseMatcher {
  final Object expected;
  //...
  public boolean matches(Object actual) {
    // compare / transform / check type / ensure: String, double, int, long
    // example via BigDecimal as seen from Mena (without checks)
    return new BigDecimal(expected).equals(new BigDecimal(actual));
  }
  // ...
}

// somewhere else:
public static IsAnyNumber is(Object expected) {
  return new IsAnyNumber(expected);
}

In your tests you then call that static method:

在您的测试中,您然后调用该静态方法:

assertThat(1, is(1L));
assertThat(1, is(1.0));
assertThat(1L, is(1));

This way you can reuse your matcher and the assert statement is more readable in the end.

通过这种方式,您可以重用匹配器,并且断言语句最终更具可读性。

Disclaimer: this is only pseudo-code and was not yet tested, but should work with some tweaking.

免责声明:这只是伪代码,尚未经过测试,但应该进行一些调整。

But beware also from Comparing Numbers in Java

但也要注意比较 Java 中的数字

回答by Stefan

Create your own assert methods and compare the double values for the primitives. If a BigDecimalis used, the primitive value has to be converted to a BigDecimal

创建您自己的断言方法并比较基元的双精度值。如果使用 a BigDecimal,则原始值必须转换为 aBigDecimal

static void assertEquals(Number number1, Number number2) {
  Assert.assertEquals(number1.doubleValue(), number2.doubleValue());
}

static void assertEquals(BigDecimal number1, BigDecimal number2) {
  if (number2.compareTo(number1) != 0) {
    Assert.fail("Values are not equal. ..... ");
  }
}

static void assertEquals(Number number1, BigDecimal number2) {
  assertEquals(new BigDecimal(number1.doubleValue()), number2);
}

static void assertEquals(BigDecimal number1, Number number2) {
  assertEquals(number2, number1);
}

It can be used this way:

它可以这样使用:

assertEquals(1, new BigDecimal("1.0"));
assertEquals(1.0d, 1);
assertEquals(new Float(1.0f), 1.0d);
assertEquals(new BigDecimal("1.00000"), new BigDecimal("1.0"));
...

回答by Stephen C

According to my reading of the JLS, the overload resolution for

根据我对 JLS 的阅读,对于

Assert.assertEquals(1,1L)

should resolve to

应该解决

Assert.assertEquals(long, long)

(For the record, assertEquals(long, long), assertEquals(float, float)and assertEquals(double, double)are applicable by strict invocation, and the first one is the most specific; see JLS 15.12.2.2. The strict invocation context allows primitive widening, but not boxing or unboxing.)

(根据记录,assertEquals(long, long)assertEquals(float, float)assertEquals(double, double)适用通过严格调用,和第一个是最具体的;参见JLS 15.12.2.2。严格调用上下文允许原始加宽,但不是拳击或取消装箱)

If (as the evidence suggests) your call is resolving to Assert.assertEquals(Object, Object), that implies that one of the operands must alreadybe a boxed type. The problem with that overload is that it is using the equals(Object)method to compare objects, and the contract for that method specifiesthat the result is falseif the objects' respective types are different.

如果(如证据所示)您的调用解析为Assert.assertEquals(Object, Object),则意味着其中一个操作数必须已经是装箱类型。该重载的问题在于它使用该equals(Object)方法来比较对象,并且该方法的约定指定结果是false对象各自的类型是否不同。

If that is what is going on in your real code, then I doubt that the suggestion of using the is(T)Matcherwill work either. The is(T)matcher is equivalent to is(equalTo(T))and the latter relies on equals(Object)...

如果这就是您的真实代码中发生的事情,那么我怀疑使用 的建议is(T)Matcher是否有效。该is(T)匹配相当于is(equalTo(T))后者依赖于equals(Object)...

Is there an existing "nice method"?

是否有现有的“好方法”?

AFAIK, no.

AFAIK,没有。

I think that the real solution is to be a bit more attentive to the types; e.g.

我认为真正的解决方案是更加关注类型;例如

 int i = 1;
 Long l = 1L;
 Assert.assertEquals(i, l);         // Fails
 Assert.assertEquals((long) i, l);  // OK - assertEquals(Object, Object)
 Assert.assertEquals((Long) i, l);  // OK - assertEquals(Object, Object)
 Assert.assertEquals(i, (int) l);   // OK - assertEquals(long, long) 
                                    //      it would bind to an (int, int) 
                                    //      overload ... it it existed.   
 Assert.assertEquals(i, (long) l);  // OK - assertEquals(long, long)

Writing a custom Matcherwould work too.

编写自定义Matcher也可以。

回答by leeyuiwah

I think to accept all eight types of numerical values (primitive and object), the method has to take string arguments. The caller will have to remember to cast the value to string by this idiom:

我认为要接受所有八种类型的数值(原始和对象),该方法必须采用字符串参数。调用者必须记住通过这个习语将值转换为字符串:

""+value

Also, in case the value is not an integer (int, Integer, long, Long) but a floating point representation (float, double, Float, Double), the method must also take a argument epsilonto tolerate imprecision due to the representation.

此外,如果该值不是整数 ( int, Integer, long, Long) 而是浮点表示 ( float, double, Float, Double),则该方法还必须接受一个参数epsilon以容忍由于表示引起的不精确性。

So here is an implementation idea (for now I ignore the cases of NaN and positive and negative zeros of double -- these can be added if a truly solid implementation is needed)

所以这是一个实现想法(现在我忽略 NaN 和 double 的正负零的情况——如果需要真正可靠的实现,可以添加这些)

private static boolean equalsNumerically(String n1String
                                        , String n2String
                                        , double epsilon) {
    try {
        Long n1Long = new Long(n1String);
        Long n2Long = new Long(n2String);
        return n1Long.equals(n2Long);
    } catch (NumberFormatException e) {
        /*
         * If either one of the number is not an integer, try comparing
         * the two as Double
         */
        try {
            Double n1Double = new Double(n1String);
            Double n2Double = new Double(n2String);
            double delta = ( n1Double - n2Double) / n2Double;
            if (delta<epsilon) {
                return true;
            } else {
                return false;
            }
        } catch (NumberFormatException e2) {
            return false;
        }
    } 
}

Testing code

测试代码

    int     primitiveInt = 1;
    long    primitiveLong = 1L;
    float   primitiveFloat = 0.999999F;
    double  primitiveDouble = 0.999999D;
    Integer objectInt = new Integer(1);
    Long    objectLong = new Long(1);
    Float   objectFloat = new Float(0.999999);
    Double  objectDouble = new Double(0.999999);

    final double epsilon = 1E-3;

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, 0)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveLong, 0): %s %s %s%n"
            , primitiveInt, primitiveLong, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, epsilon));
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveLong, epsilon)): %s %s %s%n"
            , primitiveInt, primitiveLong, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveFloat, epsilon)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveFloat, 0): %s %s %s%n"
            , primitiveInt, primitiveFloat, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveDouble, epsilon)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+primitiveDouble, epsilon): %s %s %s%n"
            , primitiveInt, primitiveDouble, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectInt, 0)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+objectInt, 0): %s %s %s%n"
            , primitiveInt, objectInt, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectLong, 0)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+objectLong"
            + ", \"\"+objectLong, 0): %s %s %s%n"
            , primitiveInt, primitiveLong, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectFloat, epsilon));
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+objectFloat, epsilon)): %s %s %s%n"
            , primitiveInt, objectFloat, epsilon);

    Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectDouble, epsilon)); 
    System.out.format("Test passed: "
            + "Assert.assertTrue(equalsNumerically(\"\"+primitiveInt"
            + ", \"\"+objectDouble, 0): %s %s %s%n"
            , primitiveInt, objectDouble, epsilon);

Test output

测试输出

Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, 0): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveLong, epsilon)): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveFloat, 0): 1 0.999999 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+primitiveDouble, epsilon): 1 0.999999 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectInt, 0): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectLong, 0): 1 1 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectFloat, epsilon)): 1 0.999999 0.001
Test passed: Assert.assertTrue(equalsNumerically(""+primitiveInt, ""+objectDouble, 0): 1 0.999999 0.001