ConcurrentHashMap.newKeySet() vs Collections.newSetFromMap()

Java 8 представила новый способ получения параллельной реализации Set

// Pre-Java-8 way to create a concurrent set
Set<String> oldStyle = Collections.newSetFromMap(new ConcurrentHashMap<>());
// New method in Java 8
Set<String> newStyle = ConcurrentHashMap.newKeySet();

Есть ли причина предпочитать новый метод?

Любые преимущества/недостатки?

Ответ 1

ConcurrentHashMap.newKeySet() должен быть несколько более эффективным, поскольку удаляет один уровень косвенности. Collections.newSetFromMap(map) в основном основана на перенаправлении операций на map.keySet(), но ConcurrentHashMap.newKeySet() очень близок к map.keySet() (только с поддержкой дополнений).

Что касается функциональности, я не вижу разницы.

Ответ 2

ConcurrentHashMap.newKeySet() - это всего лишь часть функции, которая намного шире, чем Collections.newSetFromMap(new ConcurrentHashMap<>()).

Разница становится понятной, если вы посмотрите на этот пример:

Set<String> set=new ConcurrentHashMap<String,String>().keySet("hello");

Вместо сопоставления с Boolean.TRUE вы добавляете значение "hello" при добавлении нового значения в Set.

Вот почему возвращаемый Set имеет тип ConcurrentHashMap.KeySetView. У этого типа есть дополнительные методы для запроса карты поддержки, а также какое значение будет использовано при добавлении новых ключей.


Таким образом, хотя ConcurrentHashMap.newKeySet() выглядит так же, как Collections.newSetFromMap(new ConcurrentHashMap<>()), существует семантическая разница, которая, по словам последнего, не должна использовать карту впоследствии, в то время как первая является частью функции, которая предназначен для взаимодействия с картой.

См. Collections.newSetFromMap:

Указанная карта должна быть пустой во время вызова этого метода и не должна быть доступна сразу после возвращения этого метода.

На самом деле, даже не указано, что Collections.newSetFromMap будет использовать Boolean.TRUE для добавленных значений - вы никогда не должны иметь дело с этим в любом случае...


Это также может быть полезно, когда вы хотите передать Set для кода, который явно запрашивает ConcurrentHashMap.KeySetView.


Если вы используете результат только с использованием типа времени компиляции Set only, существует вероятность того, что код, получающий этот Set будет использовать instanceof/type, чтобы узнать, что результат ConcurrentHashMap.newKeySet() поддерживается ConcurrentHashMap тогда как результат Collections.newSetFromMap скажет вам. С другой стороны, это также позволяет коду делать непреднамеренные вещи с поддержкой карты таким образом...