Предупреждение для общих varargs - PullRequest
7 голосов
/ 23 ноября 2010

Я объявил следующий метод:

private void mockInvokeDBHandler(Map<String, Object>... rows) {
    List<Map<String, Object>> allRows = Arrays.asList(rows));
    // rest of method omitted
}

Он вызывается клиентами, использующими что-то вроде

Map<String, Object> row1 = new HashMap<String, Object>();
Map<String, Object> row2 = new HashMap<String, Object>();

mockInvokeDBHandler(row1, row2);

Однако последняя строка, показанная выше, генерирует предупреждение

Безопасность типов: для параметра varargs создается общий массив Map

Я не до конца это понимаю, но думаю, это потому, что параметры varargs преобразуются в массивы, и этоплохая идея иметь массив, тип которого является родовым классом (потому что дженерики инвариантны, а массивы нет).

Я мог бы решить эту проблему, переименовав метод в

private void mockInvokeDBHandler(List<Map<String, Object>> rows) {
}

Но это возлагает бремя помещения объектов строк в список на клиенте, чего я бы предпочел избежать.Есть ли лучшее решение?

Ответы [ 4 ]

12 голосов
/ 23 ноября 2010

Чтобы передать аргументы методу varargs, компилятор поместит аргументы в массив.

Предупреждение состоит в том, что вы должны знать, что компилятор не может гарантировать, что каждый из элементов в массиве - каждый из аргументов метода varags - действительно является Map<String, Object>.

Это немного раздражающее предупреждение, потому что нет способа обойти это, кроме как переопределить сигнатуру метода, чтобы не использовать varargs. ИМО безопасно игнорировать до тех пор, пока вы достаточно уверены в фактических типах этих аргументов во время выполнения (которыми в данном случае вы являетесь).

4 голосов
/ 23 ноября 2010

Нет способа избежать этого предупреждения, кроме добавления @SuppresWarning("unchecked") к методу :)

Поскольку вы говорите, что это частный метод, в этом случае нет «клиентов», и вы контролируете метод, поэтому игнорирование предупреждения кажется разумным.

Несколько раз, когда я создавал методы, принимающие параметризованные типы в качестве параметра varargs, я создавал некоторые перегрузки:

void mockInvokeDBHandler(Map<String, Object> map1)
void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2)
void mockInvokeDBHandler(Map<String, Object> map1, Map<String, Object> map2, Map<String, Object>... othermaps)

Это может избежать некоторых предупреждений, в зависимости от того, сколько аргументов предоставлено.

3 голосов
/ 02 августа 2017

Для любого, кто приземлится здесь, ответы немного старые. Java 7 представила аннотацию @Safevarargs для решения этой проблемы:

@SafeVarargs
private void mockInvokeDBHandler(Map<String, Object>... rows) {

Из Javadoc:

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

2 голосов
/ 23 ноября 2010

Вы можете снизить нагрузку на использование List вместо varargs, используя некоторый интерфейс компоновщика (например, такой как тот, который я использую ).Используя этот CollectionBuilder, он мог бы выглядеть примерно так:

mockInvokeDBHandler(CollectionBuilder.<Map<String, Object>>list().add(map1).add(map2).get());

он красивее без общих аргументов:

import static at.molindo.utils.collections.CollectionBuilder.list

List<String> list = list(String.class).add("foo").addAll(set).get();

Это, конечно, дольше, чем решение varargs, но в любом случае довольно удобно иногда.

...