Элегантный способ преодолеть Невероятный тип аргумента для equals (): поток <String>не связан со строкой - PullRequest
0 голосов
/ 18 февраля 2019

Я ищу элегантный способ преодоления при сравнении любого объекта Wrapper с Stream.

Рабочая ссылка Github: https://github.com/vishwaratna/Unlikely-argument-type-for-equals-Stream-String-/commit/d803f77c923e81fe7531ecb467561ac785d7aca5

Ссылка на вопрос : Фильтрация ключей от атрибута карты к списку в java-8

Недавно я столкнулся с этим при сравнении члена List с ключом Map.Я знаю, что есть другие способы сравнивать, не делая то, что я делаю, но я ищу общий кастинг, если он доступен.

List<student> stulist = Arrays.asList(new student("1", "vishwa",null),
                                              new student("3", "Ravi",null),
                                              new student("2", "Ram",null));

        Map<String,String> map = new HashMap() {{
             put("1","20");
             put("2","30");
           }};

System.out.println( stulist.stream()
                    .filter(s->s.getId()
                    .equals(map.entrySet()
                    .stream() 
                    .map(Map.Entry::getKey)))
                    .count());

Мойкод компилируется правильно, но вывод идет как "0" , тогда как я ожидаю вывод как 2 .

Я уверен, что это связано с типомнесоответствие, но почему компилятор не выдает ошибку ??

Предупреждение, что я получаю: Unlikely argument type for equals(): Stream<String> seems to be unrelated to String

Ответы [ 3 ]

0 голосов
/ 18 февраля 2019

Вы можете использовать map.containsKey, чтобы избежать запуска потока в наборе записей для каждой записи студента:

long count = stulist.stream().map(student::getId).filter(map::containsKey).count();

Вы получаете предупреждение, потому что обнаруживается, что вы тестируете String.equals(Stream<String>)что, конечно, может быть ошибкой (в вашем примере, это, безусловно, так).

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

long count = stulist.stream()
                .filter(s -> map.entrySet()
                                .stream()
                                .map(Map.Entry::getKey)
                                .anyMatch(s.getId()::equals))
                .count();
0 голосов
/ 19 февраля 2019

По сути, чтобы понять, почему компилятор не выдает ошибку, вам нужно посмотреть String.equals () реализация метода

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

Теперь вернемся к этой строке:

s.getId().equals(map.entrySet().stream().map(Map.Entry::getKey))

Как мы знаем, s.getId() имеет тип String, а map.entrySet().stream().map(Map.Entry::getKey) имеет тип Stream<String>.

Поскольку Stream<String> не instanceof String, ясно, что метод String.equals() будет возвращать false каждый раз, когда s.getId() сравнивается с map.entrySet().stream().map(Map.Entry::getKey) (следовательно, 0 считается в конце).И компилятор не выдает ошибку, потому что ничего противозаконного на самом деле не произошло (с учетом реализации String.equals()).

Также, возможно, самый чистый способ найти count без предупреждений мог быбыть:

System.out.println(
  stulist.stream()
         .map(Student::getId)
         .filter(map::containsKey)
         .count());
0 голосов
/ 18 февраля 2019

Во-первых, то, что вы, возможно, намереваетесь сделать, может быть:

System.out.println(stulist.stream()
        .filter(s -> map.keySet().contains(s.getId()))
        .count());

Во-вторых, сравнение с использованием equals в вашем коде некорректно, поскольку оно выполняется между объектами двух разных типов String иStream<String>.

// here the 's.getId' is a String while 'map.entrySet()...map()' provides 'Stream<String>'
.filter(s -> s.getId().equals(map.entrySet().stream().map(Map.Entry::getKey)))
...