Разница между реализацией функционального интерфейса, используемого вместе с потоками - PullRequest
0 голосов
/ 12 апреля 2020

Я пытаюсь понять работу фильтрации потока здесь. Ниже приведены два подхода для фильтрации дубликатов из List из String с. (Я не хочу использовать отдельное ключевое слово в демонстрационных целях)

List<String> list = new ArrayList(){{add("abc");add("abc");add("abcd");}};
List<String> list1 = list.parallelStream().filter(e->{
                                           Set<String> seen = ConcurrentHashMap.newKeySet();
                                           return seen.add(e.getLastName());
                    }).collect(Collectors.toList());

Вышеописанный подход не работает, так как каждый раз создается новый экземпляр Set.

List<String> list2  =    
list.parallelStream().filter(distincyByKey(e>e.getLastName())).collect(Collectors.toList());

    public static <T> Predicate<T> distincyByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen =  ConcurrentHashMap.newKeySet();
        System.out.println("testttttttttttt");
        return t -> seen.add(keyExtractor.apply(t));
    }

Этот подход работает. Не уверен, в чем разница между подходами 1 и 2. Я вижу, что distincyByKey - это метод stati c, но как это влияет?

Ответы [ 2 ]

1 голос
/ 12 апреля 2020

Разница между ними в точности равна вашим Set объектам.

В первом фрагменте кода seen создается предикатом. Предикат вызывается для каждого элемента. Это означает, что каждый раз, когда вызывается предикат, создается заданный экземпляр. Во втором случае набор создается с помощью distincyByKey(), который запускается только один раз при создании потока.

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

public static <T> Predicate<T> distincyByKey(Function<? super T, ?> keyExtractor) {
    return t -> {
        Set<Object> seen =  ConcurrentHashMap.newKeySet();
        return seen.add(keyExtractor.apply(t));
    }
}

Эта версия была бы такой же сломанной, как и ваша первая реализация.

0 голосов
/ 12 апреля 2020

Ваш первый фрагмент создает новый экземпляр Set каждый раз, когда выполняется тело лямбда-выражения, что означает один раз для каждого элемента Stream. Поэтому каждый раз, когда фильтр применяется к элементу Stream, он добавляет элемент к другому экземпляру Set, поэтому он не может отфильтровать дубликаты.

Во втором фрагменте * Экземпляр 1007 * создается один раз, когда выполняется distincyByKey(). Когда фильтр оценивается для каждого элемента Stream, выполняется лямбда-тело просто seen.add(keyExtractor.apply(t), и оно всегда выполняется для одного и того же Set экземпляра.

Вы можете добиться того же поведения без static метод путем создания экземпляра Set вне конвейера Stream или использования ссылки на метод:

Set<String> seen = ConcurrentHashMap.newKeySet();
List<String> list1 = 
    list.parallelStream().filter(e-> seen.add(e)).collect(Collectors.toList());

или

List<String> list1 = 
    list.parallelStream().filter(ConcurrentHashMap.newKeySet()::add).collect(Collectors.toList());

РЕДАКТИРОВАТЬ: я удалил getLastName() вызов метода из кода, поскольку ваш Stream является Stream<String>, а String s не имеют getLastName() метода. Я предполагаю, что вы перепутали некоторые фрагменты кода.

...