2

I am using IntelliJ IDEA 2018.1.3 Ultimate Edition, and need to compare to large integers (large enough to not fit into a long, for example 20180531234240565494) represented as strings:

public int compareNumeric(String compareTo) {
    return new BigInteger(version).compareTo(new BigInteger(compareTo));
}

This is the solution proposed here, which I always thought was the correct way to create a BigInteger from a String.

However, IntelliJ gives the following warning, through a Sonar plugin:

Constructors should not be used to instantiate "String", "BigInteger", "BigDecimal" and primitive-wrapper classes

squid:S2129
Constructors for Strings, BigInteger, BigDecimal and the objects used to wrap primitives should never be used. Doing so is less clear and uses more memory than simply using the desired value in the case of strings, and using valueOf for everything else.
Further, these constructors are deprecated in Java 9, which is an indication that they will eventually be removed from the language altogether.

Noncompliant Code Example

String empty = new String(); // Noncompliant; yields essentially "", so just use that.
String nonempty = new String("Hello world"); // Noncompliant
Double myDouble = new Double(1.1); // Noncompliant; use valueOf
Integer integer = new Integer(1); // Noncompliant
Boolean bool = new Boolean(true); // Noncompliant
BigInteger bigInteger = new BigInteger("1"); // Noncompliant
BigDecimal bigDecimal = new BigDecimal(1.1); // Noncompliant<br/>

Compliant Solution

String empty = "";
String nonempty = "Hello world";
Double myDouble = Double.valueOf(1.1);
Integer integer = Integer.valueOf(1);
Boolean bool = Boolean.valueOf(true);
BigInteger bigInteger = BigInteger.valueOf(1);
BigDecimal bigDecimal = BigDecimal.valueOf(1.1);

First of all, I don't see the constructor being deprecated in Java 9, is Sonar wrong here?

Am I doing the comparison wrong and triggered a false positive, or should the comparison be made in some other way?

The only other way I can think of is to compare the strings directly, but that would also force me to first check that the strings are numeric.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Magnilex
  • 11,584
  • 9
  • 62
  • 84
  • "Compliant Solution `BigInteger bigInteger = BigInteger.valueOf(1);`" – Andy Turner Jun 05 '18 at 08:20
  • it has nothing to do with it being deprecated or not, they are merely saying the .valueOf(125); method is a better approach. the reason why, you already copy pasted in your question – Stultuske Jun 05 '18 at 08:21
  • 6
    The suggested solution of `BigInteger.valueOf()` is only applicable for values that can fit in `long`, so I'd ignore that warning (assuming your `String`s represent values that can't fit in a `long`) – Eran Jun 05 '18 at 08:21
  • I guess you also want to use the parameter `compareTo`. – Andy Turner Jun 05 '18 at 08:21
  • @AndyTurner I could have done that, but as Eran points out, the number don't fit into a `long`. And thanks for pointing out the typo. – Magnilex Jun 05 '18 at 08:27
  • 1
    @Stultuske The warning mentions that these constructors have been deprecated, but I don't see `new BigInteger(String)` being deprecated. – Magnilex Jun 05 '18 at 08:28
  • 1
    @Eran or assuming your string is not a constant, in which case you don't know what value it contains. – Erwin Bolwidt Jun 05 '18 at 08:29
  • I missed that. Maybe they had planned to deprecate them, but it didn't get into this release, while sonar had already updated their checks – Stultuske Jun 05 '18 at 08:31
  • @ErwinBolwidt you usually have some expectations regarding the size of the input you wish to support. If you expect your Strings to always hold a numeric value that can fit in a long, you can parse them with `Long.parseLong()`, which will throw an exception if you receive unexpected input. – Eran Jun 05 '18 at 08:36
  • @Magnilex what is the type and value of `version`? – DodgyCodeException Jun 05 '18 at 08:39
  • @DodgyCodeException I updated my question with an example of how the strings look. – Magnilex Jun 05 '18 at 08:43
  • 1
    @Stultuske they're not deprecated in Java 10 either. They are not even planned to be deprecated in [Java 11](https://download.java.net/java/early_access/jdk11/docs/api/java.base/java/math/BigInteger.html#%3Cinit%3E(java.lang.String)). It's more likely that `BigInteger` was incorrectly thrown into the same pot as `Integer` and `Long` constructors which _are_ deprecated. – DodgyCodeException Jun 05 '18 at 08:45
  • 1
    By the way, your `20180531234240565494` looks suspiciously like a date and time string. Are you sure `BigInteger` is the best type to use here? – Sweeper Jun 05 '18 at 08:47
  • @Sweeper I does, doesn't it? True, it does come from a timestamp in this particular case. However, I cannot really assume that. But well spotted. – Magnilex Jun 05 '18 at 08:49

1 Answers1

3

You are hitting this problem SONARJAVA-2740 which has been fixed in latest SonarJava version which should be publicly available in a few days.

agabrys
  • 8,728
  • 3
  • 35
  • 73
benzonico
  • 10,635
  • 5
  • 42
  • 50