2015-07-27 3 views
2

Я добавляю значения в HashSet и получаю NullPointerException в методе compareTo.Почему HashSet вызывает метод compareTo и вызывает NullPointerException

java.lang.NullPointerException 
    at com.fiveIQ.document.Link.compareTo(Link.java:226) 
    at com.fiveIQ.document.Link.compareTo(Link.java:16) 
    at java.util.HashMap.compareComparables(HashMap.java:371) 
    at java.util.HashMap$TreeNode.treeify(HashMap.java:1920) 
    at java.util.HashMap.treeifyBin(HashMap.java:771) 
    at java.util.HashMap.putVal(HashMap.java:643) 
    at java.util.HashMap.put(HashMap.java:611) 
    at java.util.HashSet.add(HashSet.java:219) 
    at com.fiveIQ.crawlData.parser.EightyLegJsonParser.parse(EightyLegJsonParser.java:51) 
    at com.fiveIQ.crawlData.processor.CrawlDataParser.process(CrawlDataParser.java:57) 
    at com.fiveIQ.crawlData.processor.CrawlDataUploader.upload(CrawlDataUploader.java:31) 
    at com.fiveIQ.crawlData.processor.CrawlDataUploaderExecutor$1.run(CrawlDataUploaderExecutor.java:85) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 

Вот мой метод compareTo. Значения updatedOn - null. Но я не понимаю, почему HashSet звонит compareTo?

@Override 
public int compareTo(Link o) 
{ 
    return o.updatedOn.compareTo(this.getUpdatedOn()); 
} 
+0

Независимо от того, почему *, это * есть *. Вы уверены, что 'o' не' null ', когда вы сначала собираетесь что-то вставить? – Makoto

+0

Ваш метод compareTo не должен бросать NPE, если переданный аргумент не равен «null», [в документации] (http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable. HTML). –

ответ

7

Я полагаю, вы используете Java 8. Поскольку Java 8, HashMap реализации (который используется HashSet) изменяются для защиты от столкновений: если же ведро имеет слишком много элементов и ключи Comparable, то это ковш преобразуется в дерево RB (аналогично TreeMap), чтобы выполнить поиск в этом логарифмическом ковше вместо линейного. Это также защищает приложение от вредоносных попыток отравить HashMaps конфликтующими ключами, вызывающими атаки типа «отказ в обслуживании». См. JEP 180.

4

При определенных обстоятельствах более новые версии HashMap (начиная с Java 8) пытаются использовать дерево в качестве корзины для объектов с одним и тем же хеш-кодом вместо связанного списка. Это происходит только тогда, когда ваши объекты реализуют Comparable, и он имеет полное право на это, так как ваши объекты рекламируют себя как Comparable.

Урок: если вы реализуете Comparable в вашем объекте, ваш метод compareTo() должен выполнить свой контракт, в частности, они должны обязательно только с NullPointerException, если аргумент, переданный к ним null. В вашем случае один из объектов Link имеет updatedOn, установленный в null, и это вызывает проблему. То, что вы должны иметь вместо этого что-то вроде этого:

@Override 
public int compareTo(Link o) 
{ 
    if (o.updatedOn == null) { 
     return this.updatedOn == null ? 0 : 1; //or -1, depending on whether you want null to come first or last in the ordering 
    ] 
    return o.updatedOn.compareTo(this.updatedOn); // it isn't a good idea to use getter for one object and direct field access for the other 
} 

Эта реализация не будет выпадать с NPE, но она до сих пор вопрос: что произойдет, если два различных ссылки обновляются в тот же день? Случается, что иногда они будут считаться равными. В других случаях они не будут. Ваш код провалится тонким и непредсказуемым образом.

Причиной этого является то, что updatedOn не содержит достаточно информации о Link объектов, чтобы однозначно идентифицировать их, не следует использовать в compareTo() самостоятельно.

Итак, второй урок: будьте осторожны, чтобы реализовать только Comparable, если ваши объекты имеют «естественный» порядок, который может быть получен из их свойств. Другими словами: только объекты, которые можно рассматривать как идентичные, если ни один не больше другого, равно Comparable.

+2

Есть одна вещь, о которой следует упомянуть: поскольку коллекция, основанная на хеше, прибегает к сортировке при наличии определенного количества коллизий, это может быть индикатором реализации «hashCode», столь же бедной, как реализация «compareTo». Улучшение, которое рекомендуется также ... – Holger

Смежные вопросы