Hier ist ein Beispiel dafür, was Ihre drei Methoden sein sollte.
Dies ist, was ein genannt wird MCVE(Minimal, Complete, und prüfbare Beispiel).
Das primäre Konzept ist, dass das Konstruieren einer neuen kombinierten Zeichenfolge durch Aufrufen von toString()
nicht der richtige Weg ist, equals()
und hashCode()
zu implementieren.
Dies ist vor allem aus Leistungsgründen. Mit 18 million objects hinzugefügt, um die Karte, Leistung von equals()
und hashCode()
Angelegenheiten.
Ein anderer Grund, es ist eine schlechte Idee, ist, dass toString()
möglicherweise nicht alle Werte des Objekts anzeigen, oder dass zwei verschiedene Objekte immer noch das gleiche toString()
Ergebnis, z. wenn Token Leerzeichen enthalten könnte, dann Verketten würde sie nicht in der Lage sein A B
, zu unterscheiden C
von A
, B C
.
Für das Beispiel wird ein String[]
für das Feld previousToken
verwendet, und ein Varargs-Konstruktor wird verwendet, um das Testen zu vereinfachen. Null-Token sind nicht erlaubt. Deines ist wahrscheinlich etwas anders, aber das zeigt die Konzepte.
public class NGram {
private String token;
private String[] previousToken; // could also be List<String>
public NGram(String ... allTokens) {
if (allTokens.length == 0)
throw new IllegalArgumentException("At least one token is required");
for (String s : allTokens)
if (s == null)
throw new NullPointerException();
this.token = allTokens[allTokens.length - 1];
this.previousToken = Arrays.copyOfRange(allTokens, 0, allTokens.length - 1);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
for (String s : this.previousToken)
buf.append(s).append(' ');
return buf.append(this.token).toString();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
NGram that = (NGram) obj;
return this.token.equals(that.token) &&
Arrays.equals(this.previousToken, that.previousToken);
}
@Override
public int hashCode() {
return this.token.hashCode() + 31 * Arrays.hashCode(this.previousToken);
}
}
TEST
Dies zeigt eine schnellere, kompaktere Version des Codes ein neues Objekt zu der Karte hinzuzufügen. Es ist schneller, weil es nur eine Lookup pro Add führt und kompakter gemacht durch einen ternären Operator anstelle eines if
Anweisung, die Kombination der beiden put()
Anrufe.
Es ist für eine einfacheren Tests in einer Hilfsmethode isoliert.
public static void main(String[] args) {
Map<NGram, Integer> countMap = new HashMap<>();
add(countMap, new NGram("Foo"));
add(countMap, new NGram("Bar"));
add(countMap, new NGram("Foo", "Bar"));
add(countMap, new NGram("This", "is", "a", "test"));
add(countMap, new NGram("Bar"));
System.out.println(countMap);
}
private static void add(Map<NGram, Integer> countMap, NGram ng) {
Integer counter = countMap.get(ng);
countMap.put(ng, (counter != null ? counter + 1 : 1));
}
OUTPUT
{Bar=2, Foo=1, This is a test=1, Foo Bar=1}
Wie Sie die doppelte Bar
Wert zweimal gezählt sehen können, ist.
Wenn Sie mit vielen doppelten Objekten am Ende, das heißt mit einem hohen Zählwerte, dann ist ein unveränderliches Integer
Objekt als Zähler verwendet für die Leistung nicht groß. Sie können eine int[1]
verwenden, aber eine veränderbare Helferklasse ist besser, da sie eine gute toString()
Implementierung bereitstellen kann.
private static void add(Map<NGram, Counter> countMap, NGram ng) {
Counter counter = countMap.get(ng);
if (counter == null)
countMap.put(ng, new Counter(1));
else
counter.increment();
}
private static final class Counter {
private int count;
public Counter(int count) {
this.count = count;
}
public void increment() {
this.count++;
}
public int get() {
return this.count;
}
@Override
public String toString() {
return Integer.toString(this.count);
}
}
Können Sie uns den Code aus den Methoden 'equals' und' getHashCode' zeigen? –
Vielleicht haben Sie noch nie ein 'NGram' Objekt hinzugefügt, so dass Sie nie in den Code innerhalb des' if' gehen werden? –
@KevinWallis OP hat gesagt * "Snippet ist in einer Schleife" *, also ist es wahrscheinlicher, dass 'param' in' equals() 'verwendet wird und immer eindeutig ist, z. es ist die Schleifenvariable. – Andreas