Nemít přetěžování operátorů skutečně považuji za velký problém Javy. Proč? Např. proto, že porovnávání objektů pomocí instance třídy Comparator
či porovnání objektů implementující rozhraní Comparable
je boj, který pernamentně prohrávám. Mějme např. dva datumy d1
a d2
. Pokud chci zjistit, zda platí d1 <= d2
, pak mám následující možnosti:
!d1.after(d2)
d1.compareTo(d2) <= 0
before
a after
má pouze třída java.util.Date
nikoliv obecná třída implementující rozhraní Comparable
. Pokud budeme objekty porovnávat pomocí instance Comparator
pak musíme vystačit s metodou compare
.Z tohoto důvodu jsem si udělal jednoduchý
enum
:
public enum Relation {
eq, ne, lt, le, gt, ge;
public static <C extends Comparable<? super C>> boolean rel(C c1, Relation oper, C c2) {
switch (oper) {
case eq:
return c1.compareTo(c2) == 0;
case ne:
return c1.compareTo(c2) != 0;
case lt:
return c1.compareTo(c2) < 0;
case le:
return c1.compareTo(c2) <= 0;
case gt:
return c1.compareTo(c2) > 0;
case ge:
return c1.compareTo(c2) >= 0;
}
throw new IllegalArgumentException("Unsupported operation " + oper);
}
public static <C> boolean rel(Comparator<C> comp, C c1, Relation oper, C c2) {
switch (oper) {
case eq:
return comp.compare(c1, c2) == 0;
case ne:
return comp.compare(c1, c2) != 0;
case lt:
return comp.compare(c1, c2) < 0;
case le:
return comp.compare(c1, c2) <= 0;
case gt:
return comp.compare(c1, c2) > 0;
case ge:
return comp.compare(c1, c2) >= 0;
}
throw new IllegalArgumentException("Unsupported operation " + oper);
}
}
Díky použití tohoto enumu mohu přepsat výše uvedený příklad porovnávání dvou datumů do podoby:rel(d1, le, d2)
(pokud použijeme statické importy na metodu rel
a instanci enumu le
). Protože se mi tento zápis ještě stále nezdál dostatečně výmluvný, použil jsem další vylepšení (stačí jej přidat do výše uvedeného enumu):
protected static final Map<String, Relation> S2R;
static {
Map<String, Relation> tmp = new TreeMap<String, Relation>();
tmp.put("==", eq);
tmp.put("!=", ne);
tmp.put("<=", le);
tmp.put("<", lt);
tmp.put(">=", ge);
tmp.put(">", gt);
S2R = unmodifiableMap(tmp);
}
public static <C extends Comparable<? super C>> boolean rel(C c1, String oper, C c2) {
return rel(c1, S2R.get(oper), c2);
}
public static <C> boolean rel(Comparator<C> comp, C c1, String oper, C c2) {
return rel(comp, c1, S2R.get(oper), c2);
}
Nyní dostaneme již poměrně elegantní zápis:rel(d1, "<=", d2)
Je škoda, že Java nemá přetěžování operátorů, které nás vede k takovýmto vylepšením. Např. Groovy si umí poradit a operace porovnání umí zavolat nad objekty implementující Comparable
. Scala je na tom podobně díky možnosti přetížení operátorů.