解决的办法是不要给 Strings 太多的权力,而是创建一个可以保存值的类,例如 Strings,而是带有信息的值,可以使用的信息,包括用于比较彼此的信息。
例如,在这种情况下,我会创建一个 Tenor 类,它包含一个 int 值以及表示持续时间(例如,周、月、年)的东西。现在我可以使用字符串来表示持续时间,但由于只有有限的值可以工作,所以使用枚举来表示持续时间会更好也更更安全。因此,例如,可以像这样创建一个枚举:
public enum Duration {
SPOT("SPOT", 0), WEEK("W", 1), MONTH("M", 4), YEAR("Y", 52);
private Duration(String abbreviation, int weeks) {
this.abbreviation = abbreviation;
this.weeks = weeks;
}
private String abbreviation;
private int weeks;
public String getAbbreviation() {
return abbreviation;
}
public int getWeeks() {
return weeks;
}
}
代表我们的持续时间。然后 Tenor 字段看起来像:
public class Tenor {
private int value;
private Duration duration;
使用 getter、setter、toString 等...
但我们也想让 Tenor 实现 Comparable 接口,或者更具体地说,Comparable<Tenor> 接口,所以它可能看起来像这样:
public class Tenor implements Comparable<Tenor> {
private int value;
private Duration duration;
public Tenor(Duration duration) {
this(duration, 0);
}
public Tenor(Duration duration, int value) {
this.duration = duration;
this.value = value;
}
@Override
public int compareTo(Tenor o) {
int weeks = value * duration.getWeeks();
int otherWeeks = o.value * o.duration.getWeeks();
return Integer.compare(weeks, otherWeeks);
}
// getters, setters, toString...
}
在这里,我们可以计算 this Tenor 以及另一个 o Tenor 参数的周数,并使用 Integer.compare(...) 直接比较它们
我还想要一个方法,也许是 Tenor 类的静态方法,可以将 String 转换为 Tenor。这会有点棘手,并且需要使用正则表达式,以及抛出异常,如果转换出错,最好是“检查”异常。
可测试的版本(尚未使用检查的异常)可能如下所示:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TenorTest {
public static void main(String[] args) {
String[] tests = {"SPOT", "1W","2W","10Y", "15Y", "1M", "1Y", "20Y", "2Y", "30Y", "3M", "5Y", "6M", "9M"};
List<Tenor> tenors = new ArrayList<>();
for (String text : tests) {
tenors.add(Tenor.toTenor(text));
}
System.out.println(tenors);
// sort the collection and then repeat the printout
Collections.sort(tenors);
System.out.println(tenors);
}
}
public class Tenor implements Comparable<Tenor> {
private int value;
private Duration duration;
public Tenor(Duration duration) {
this(duration, 0);
}
public Tenor(Duration duration, int value) {
this.duration = duration;
this.value = value;
}
@Override
public int compareTo(Tenor o) {
int weeks = value * duration.getWeeks();
int otherWeeks = o.value * o.duration.getWeeks();
return Integer.compare(weeks, otherWeeks);
}
public Duration getDuration() {
return duration;
}
public int getValue() {
return value;
}
@Override
public String toString() {
if (duration == Duration.SPOT) {
return Duration.SPOT.getAbbreviation();
} else {
return Integer.toString(value) + duration.getAbbreviation();
}
}
public static Tenor toTenor(String text) {
Tenor tenor = null;
int value = -1;
Duration duration = null;
text = text.trim().toUpperCase();
String regex = "(?<=\\d)(?=\\D)";
String[] tokens = text.split(regex);
if (tokens.length == 1) {
if (tokens[0].equals(Duration.SPOT.getAbbreviation())) {
tenor = new Tenor(Duration.SPOT, 0);
}
} else if (tokens.length == 2) {
try {
value = Integer.parseInt(tokens[0]);
for (Duration d : Duration.values()) {
if (d.getAbbreviation().equals(tokens[1])) {
duration = d;
}
}
if (duration != null) {
tenor = new Tenor(duration, value);
}
} catch (NumberFormatException e) {
// ignore
}
}
if (tenor != null) {
return tenor;
} else {
// TODO: change this to a custom checked exception
String txt = "For text \"" + text + "\"";
throw new IllegalArgumentException(txt);
}
}
}
所以,在运行这个程序时,我看到了这个输出:
[SPOT, 1W, 2W, 10Y, 15Y, 1M, 1Y, 20Y, 2Y, 30Y, 3M, 5Y, 6M, 9M]
[SPOT, 1W, 2W, 1M, 3M, 6M, 9M, 1Y, 2Y, 5Y, 10Y, 15Y, 20Y, 30Y]
第一行显示未排序的输出,第二行显示排序后的输出