Generics hell: hamcrest matcher как параметр метода - программирование
Подтвердить что ты не робот

Generics hell: hamcrest matcher как параметр метода

Итак, пусть список строк и функция, которая принимает совпадение Hamcrest и возвращает результат метода matches() предоставленного совпадения:

public boolean matchIt(final Matcher<? super List<String>> matcher) {
    final List<String> lst = obtainListFromSomewhere();
    return matcher.matches(lst);
}

Пока все хорошо. Теперь я могу легко позвонить:

matchIt(empty());
matchIt(anything());
matchIt(hasItem("item"));
matchIt(everyItem(equalToIgnoringCase("item")));

... так как все эти статические методы factory создают набор, который соответствует сигнатуре метода Matcher<? super List<String>>.

Однако, я считаю, что метод-совместитель, который принимает итерацию объектов, должен быть принят также с помощью метода matchIt():

matchIt(everyItem(anything()));

Итак, я наивно изменил подпись метода matchIt():

public boolean matchIt(final Matcher<? super List<? super String>> matcher);

Но это совсем не работает. Он не только не принимает everyItem(anything()), он даже не принимает ранее правильную версию everyItem(equalToIgnoringCase("item")) say (версия компилятора 1.7.0_05):

actual argument Matcher<Iterable<String>> cannot be converted to Matcher<? super List<? super String>> by method invocation conversion

Что? Так что здесь не так? Является ли это сигнатурой метода matchIt() или является неправильной сигнатурой everyItem() Hamcrest? Или это просто система дженериков Java не подлежит ремонту? Большое спасибо за ваши комментарии!

ИЗМЕНИТЬ @rlegendi мое намерение здесь состоит в том, чтобы предоставить интерфейс для клиента для добавления и выполнения предикатов о списке. Это метод matchIt(). Вызов matchIt(anything()) имеет смысл в этом сценарии, клиент хочет знать, есть ли список. Вызов matchIt(empty()) означает, что клиент хочет знать, пуст ли список. И наоборот, для matchIt(everyItem(equalToIgnoringCase("item"))) и matchIt(hasItem("item")).

Моя цель состоит в том, чтобы иметь лучшую подпись метода matchIt(). Matcher<? super List<String>> отлично работает для всех предыдущих сценариев. Тем не менее, я считаю, что клиенту должно быть разрешено добавлять также Matcher<Iterable<Object>> -элементы (например, matchIt(everyItem(notNullValue()) имеет смысл здесь, клиент хочет знать, не является ли каждый элемент String списка нулевым).

Однако я не могу найти правильную подпись, matchIt(Matcher<? super List<? super String>>) не работает для everyItem(notNullValue());

Я использую Hamcrest 1.3.

ИЗМЕНИТЬ 2:

Я считаю, что нашел свое корневое недоразумение.

Выражение everyItem(anything()) возвращает объект типа Matcher<Iterable<Object>>. Поэтому я легко могу сделать Matcher<Iterable<Object>> m = everyItem(anything());

Однако я не понимаю, почему я не могу сделать Matcher<? super List<? super String>> m1 = m;. Кажется, что Matcher<Iterable<Object>> не Matcher<? super List<? super String>>, но я не понимаю, почему.

Я даже не могу сделать Matcher<? super List<?>> m1 = m;. Matcher<Iterable<Object>> не Matcher<? super List<?>>? Почему?

4b9b3361

Ответ 1

Однако, я считаю, что помощник, который принимает итерацию объектов должен быть принят методом matchIt(), а также

Нет, это неверно. Вместо Iterable рассмотрим List на данный момент. Итак, у вас есть Matcher<List<Object>>, а его метод matches принимает List<Object>. Теперь это займет List<String>? Нет. И вы, вероятно, уже знаете, почему, потому что он может добавить в список объект типа Object.

Теперь я знаю, что при именовании класса Matcher вы ожидаете, что метод matches будет доступен только для чтения и не будет мутировать список, данный ему. Однако это не гарантирует. Если это не добавляет ничего в список, правильным типом для матчи будет Matcher<List<?>>, который (1) не позволяет методу matches добавлять что-либо в список, кроме null и (2) позволит методу matches взять список любого типа.

Я считаю, что ваша текущая подпись метода public boolean matchIt(final Matcher<? super List<String>> matcher) уже позволяет Matcher<List<?>> (или Matcher<Iterable<?>>).

Ответ 2

Что-то не так с этим?

public boolean matchIt(final Matcher<? extends Iterable<String>> matcher);