Принудительный вызов с массивом для разрешения как вызов varargs - PullRequest
1 голос
/ 30 марта 2020

Хорошо, поэтому у меня есть такая функция, как

public static UnorderedList newUnorderedList(Object... items) {
    return new UnorderedList(
        stream(items)
            .peek(e -> checkNotNull(e, "Cannot create null list item"))
            .map(e -> {
                if (e instanceof Component) return newListItem((Component) e);
                if (e instanceof String) return newListItem((String) e);
                throw new IllegalArgumentException("List item must be String or Component but is neither: " + e.getClass().getName());
            }).toArray(ListItem[]::new)
    );
}

( EDIT : примечание: UnorderedList здесь - это реализация Vaadin тега html <ul>, Я не пытаюсь получить список java.)

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

Не сразу вижу элегантный выход из этого. Мне не нравится ни один из них:

  • всегда приведен к Object[]
  • , превращающий Object... в Collection<Object>

Есть ли аннотация или что-то подобное? что даст знать компилятору всегда разрешать массивы для вызовов vararg для аннотированных методов? (На объявлении метода, а не на сайтах вызовов.)

Ответы [ 3 ]

5 голосов
/ 30 марта 2020

Вы можете перегрузить метод:

public static UnorderedList newUnorderedList(Object first, Object... other) {
    return newUnorderedListImpl(Stream.concat(Stream.of(first), Arrays.stream(other)));
}
public static UnorderedList newUnorderedList(Object[] items) {
    return newUnorderedListImpl(Arrays.stream(items));
}
private static UnorderedList newUnorderedListImpl(Stream<?> items) {
    return new UnorderedList(
        items
            .peek(e -> checkNotNull(e, "Cannot create null list item"))
            .map(e -> {
                if (e instanceof Component) return newListItem((Component) e);
                if (e instanceof String) return newListItem((String) e);
                throw new IllegalArgumentException("List item must be String or Component but is neither: " + e.getClass().getName());
            }).toArray(ListItem[]::new)
    );
}

Затем вызов с существующим массивом закончится на newUnorderedList(Object[] items), тогда как фактический вызов varargs закончится на newUnorderedList(Object first, Object... other), даже если только один аргумент был указан, пока этот аргумент не является массивом. Поскольку предполагается, что единственным аргументом является String или Component, это не проблема.

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

public static UnorderedList newUnorderedList() {
    return newUnorderedListImpl(Stream.empty());
}
0 голосов
/ 30 марта 2020

От вашего вопроса, я думаю, вы хотите сделать следующее:

Object [] items = new Object [x];
items [0] = new Object [] {"Object1", "Object2", "Object3"};
var result = newUnorderedList( items );

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

var result = newUnorderedList( items [0] );

вернул бы 3 элемента для result.

Нет аннотации, которая заставляла бы обрабатывать отдельный массив как один элемент вместо списка элементов. Веселитесь с такой подписью:

Object function( Object [] ... );
0 голосов
/ 30 марта 2020

Вы создаете UnorderedList неправильным способом.

Предполагается, что это коллекция:

    Object[] objects = new Object[]{1, "hello", "there", "george"};
    LinkedList<AtomicReference<?>> list = Arrays.stream(objects)
            .filter(Objects::nonNull)
            .map(e -> {
                if (e instanceof Integer) return new AtomicReference<>(e);
                if (e instanceof StringBuilder) return new AtomicReference<>(e);
                throw new IllegalArgumentException("PAIN");
            })
            .collect(Collectors.toCollection(LinkedList::new));
...