Статьи

Безопасные для типов пустые коллекции в Java

Я уже писал в блоге об утилите класса Java Collections и специально писал об использовании методов коллекций emptyList (), emptyMap () и emptySet (). В этой статье я рассмотрю иногда тонкие, но существенные различия между использованием соответствующих полей класса Collections для доступа к пустой коллекции и использованием соответствующих методов класса Collections для доступа к пустой коллекции.

Следующий код демонстрирует прямой доступ к полям Collections для указания пустых коллекций.

Использование полей коллекций для пустых коллекций

01
02
03
04
05
06
07
08
09
10
11
/**
 * Instantiate my collections with empty versions using Collections fields.
 * This will result in javac compiler warnings stating 'warning: [unchecked]
 * unchecked conversion'.
 */
public void instantiateWithEmptyCollectionsFieldsAssigment()
{
   this.stringsList = Collections.EMPTY_LIST;
   this.stringsSet = Collections.EMPTY_SET;
   this.stringsMap = Collections.EMPTY_MAP;     
}

Приведенный выше код компилируется с помощью javac , но приводит к появлению предупреждающего сообщения (генерируемого в этом случае NetBeans и Ant)

1
2
3
4
-do-compile:
    [javac] Compiling 1 source file to C:\java\examples\typesafeEmptyCollections\build\classes
    [javac] Note: C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java uses unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.

Указание -Xlint: не отмечено в качестве аргумента javac (в данном случае через javac.compilerargs=-Xlint:unchecked в файле project.properties NetBeans) помогает получить более конкретные предупреждающие сообщения для ранее перечисленного кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
[javac] Compiling 1 source file to C:\java\examples\typesafeEmptyCollections\build\classes
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:27: warning: [unchecked] unchecked conversion
[javac]       this.stringsList = Collections.EMPTY_LIST;
[javac]                                     ^
[javac]   required: List<String>
[javac]   found:    List
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:28: warning: [unchecked] unchecked conversion
[javac]       this.stringsSet = Collections.EMPTY_SET;
[javac]                                    ^
[javac]   required: Set<String>
[javac]   found:    Set
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:29: warning: [unchecked] unchecked conversion
[javac]       this.stringsMap = Collections.EMPTY_MAP;     
[javac]                                    ^
[javac]   required: Map<String,String>
[javac]   found:    Map

NetBeans также отобразит эти предупреждения, если в его параметрах установлен соответствующий флажок. Следующие три изображения демонстрируют, что установлена ​​соответствующая подсказка для просмотра этих предупреждений в NetBeans, и предоставляют пример того, как NetBeans представляет приведенный выше код с предупреждениями.

К счастью, легко воспользоваться утилитой класса Collections и получить доступ к пустым коллекциям безопасным способом, который не приведет к этим предупреждениям javac и соответствующим подсказкам NetBeans. Этот подход заключается в использовании методов Collections , а не ее полей . Это продемонстрировано в следующем простом листинге кода.

Использование методов коллекций для пустых коллекций

01
02
03
04
05
06
07
08
09
10
/**
 * Instantiate my collections with empty versions using Collections methods.
 * This will avoid the javac compiler warnings alluding to 'unchecked conversion'.
 */
public void instantiateWithEmptyCollectionsMethodsTypeInferred()
{
   this.stringsList = Collections.emptyList();
   this.stringsSet = Collections.emptySet();
   this.stringsMap = Collections.emptyMap();
}

Приведенный выше код скомпилируется без предупреждения, и подсказки NetBeans также не будут отображаться Документация Javadoc для каждого поля класса Collections не описывает причину появления этих предупреждений для полей, но документация для каждого из методов с одинаковыми именами обсуждает это. В частности, документация для каждого состояния Collections.emptyList () , Collections.emptySet () и Collections.emptyMap () : «(В отличие от этого метода поле не обеспечивает безопасность типов.)»

Использование методов Collections для пустых коллекций, показанных в последнем листинге кода, обеспечивало безопасность типов без необходимости явно указывать типы, хранящиеся в этой коллекции, потому что тип был выведен путем использования методов Collections в назначениях для известных и уже объявленных атрибутов экземпляра с явно указанные типы элементов. Если тип не может быть выведен, ошибки компилятора будут возникать при использовании методов Collections без явно определенного типа. Это показано на следующем снимке экрана с попыткой сделать это в NetBeans.

Конкретное сообщение об ошибке компилятора:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:62: error: method populateList in class Main cannot be applied to given types;
[javac]       populateList(Collections.emptyList());
[javac]       ^
[javac]   required: List<String>
[javac]   found: List<Object>
[javac]   reason: actual argument List<Object> cannot be converted to List<String> by method invocation conversion
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:63: error: method populateSet in class Main cannot be applied to given types;
[javac]       populateSet(Collections.emptySet());
[javac]       ^
[javac]   required: Set<String>
[javac]   found: Set<Object>
[javac]   reason: actual argument Set<Object> cannot be converted to Set<String> by method invocation conversion
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:64: error: method populateMap in class Main cannot be applied to given types;
[javac]       populateMap(Collections.emptyMap());
[javac]       ^
[javac]   required: Map<String,String>
[javac]   found: Map<Object,Object>
[javac]   reason: actual argument Map<Object,Object> cannot be converted to Map<String,String> by method invocation conversion
[javac] 3 errors

Эти ошибки компилятора исключаются, а безопасность типов достигается путем явного указания типов элементов коллекций в коде. Это показано в следующем листинге кода.

Явное указание типов элементов с помощью пустых методов коллекций

01
02
03
04
05
06
07
08
09
10
11
/**
 * Pass empty collections to another method for processing and specify those
 * empty methods using Collections methods. This will result in javac compiler
 * ERRORS unless the type is explicitly specified.
 */
public void instantiateWithEmptyCollectionsMethodsTypeSpecified()
{
   populateList(Collections.<String>emptyList());
   populateSet(Collections.<String>emptySet());
   populateMap(Collections.<String, String>emptyMap());
}

Методы класса Collections для получения пустых коллекций предпочтительнее использования полей с одинаковыми именами Collections для той же цели из-за безопасности типов, которую обеспечивают методы. Это позволяет лучше использовать статическую систему типов Java, ключевую тему таких книг, как Effective Java . Приятным побочным эффектом является удаление беспорядочных предупреждений и помеченных подсказок NetBeans, но чем важнее результат, тем лучше и безопаснее код.

Ссылка: Безопасные для типов Пустые Коллекции в Java от нашего партнера JCG Дастина Маркса в блоге Inspired by Actual Events .