patternjavaMinor
Comparing a string that can hold a numeric value
Viewed 0 times
cancomparingnumericvalueholdthatstring
Problem
I am refactoring a part of big old system developed in Java. I came across a situation where we are migrating some data types, and there will be use of both types. For compatibility, as all the old part will remain using
The thing is, how is the proper way to compare this data? Does this way make any sense, or is there a simpler way to compare it, considering that
id as an int, I simply overloaded the constructor, and the old getter now parse a integer value.The thing is, how is the proper way to compare this data? Does this way make any sense, or is there a simpler way to compare it, considering that
id can be both, a number or a word.import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
public class SomeItem implements Comparable {
private String id;
public SomeItem(String id) {
this.id = id;
}
public SomeItem(int no) {
this(String.valueOf(no));
}
public String getId() {
return id;
}
public int getNo() {
return Integer.parseInt(id);
}
@Override
public int compareTo(SomeItem that) {
if (StringUtils.isNumeric(this.getId()) && StringUtils.isNumeric(that.getId())) {
return this.getNo() - that.getNo();
} else {
return this.getId().compareTo(that.getId());
}
}
}Solution
this.getNo() - that.getNo()may violate the contract of
compareTo() if the subtraction overflows or underflows which is a likely event if the compared values are integer IDs of a large set of elements.Instead you should explicitly compare the two:
return Integer.compare(this.getNo(), that.getNo());Another way to avoid numerical comparison altogether is to format numbers as fixed-width strings with a
DecimalFormat and compare the resulting strings (including some example code at the end):import java.text.DecimalFormat;
public class SomeItem implements Comparable {
private static final DecimalFormat fmt = new DecimalFormat();
static {
int len = 19; // = String.valueOf(Long.MAX_VALUE).length();
fmt.setMinimumIntegerDigits(len);
fmt.setMaximumIntegerDigits(len);
fmt.setPositivePrefix("+");
fmt.setGroupingUsed(false);
}
private String id;
public SomeItem(String id) {
this.id = id;
}
public SomeItem(int no) {
this(fmt.format(no));
}
public String getId() {
return id;
}
public int getNo() {
return Integer.parseInt(id);
}
@Override
public int compareTo(SomeItem that) {
return this.getId().compareTo(that.getId());
}
public static void main(String[] args)
{
java.io.PrintStream o = System.out;
SomeItem[] items = new SomeItem[] {
new SomeItem(1),
new SomeItem(-1),
new SomeItem(Integer.MAX_VALUE),
new SomeItem(Integer.MIN_VALUE)
};
for (SomeItem i: items)
System.out.format("id=%s, no=%+020d%n", i.getId(), i.getNo());
}
}Additionally, I based the amount of digits on
long instead of int to provide room for (future) growth. I would have replaced the latter by the former entirely if Java converted the return value of #getNo() silently from long to int.Code Snippets
this.getNo() - that.getNo()return Integer.compare(this.getNo(), that.getNo());import java.text.DecimalFormat;
public class SomeItem implements Comparable<SomeItem> {
private static final DecimalFormat fmt = new DecimalFormat();
static {
int len = 19; // = String.valueOf(Long.MAX_VALUE).length();
fmt.setMinimumIntegerDigits(len);
fmt.setMaximumIntegerDigits(len);
fmt.setPositivePrefix("+");
fmt.setGroupingUsed(false);
}
private String id;
public SomeItem(String id) {
this.id = id;
}
public SomeItem(int no) {
this(fmt.format(no));
}
public String getId() {
return id;
}
public int getNo() {
return Integer.parseInt(id);
}
@Override
public int compareTo(SomeItem that) {
return this.getId().compareTo(that.getId());
}
public static void main(String[] args)
{
java.io.PrintStream o = System.out;
SomeItem[] items = new SomeItem[] {
new SomeItem(1),
new SomeItem(-1),
new SomeItem(Integer.MAX_VALUE),
new SomeItem(Integer.MIN_VALUE)
};
for (SomeItem i: items)
System.out.format("id=%s, no=%+020d%n", i.getId(), i.getNo());
}
}Context
StackExchange Code Review Q#122950, answer score: 2
Revisions (0)
No revisions yet.