2016-03-18 5 views
8

Возможно ли выполнить множественное сопоставление по коллекции? Этот код ошибки компиляции:Java 8 множественное отображение

... in Stream cannot be applied to java.util.function.Function<capture<?>,capture<?>>

private static List<?> multipleMapping(final Collection<?> collection, final List<Function<?, ?>> functions) { 
    Stream<?> stream = collection.stream(); 
    for (Function<?, ?> function : functions) { 
     stream = stream.map(function); 
    } 
    return stream.collect(Collectors.toList()); 
} 

Я хотел бы общее решение.

+1

Выполните 'Function's все возвращают тот же тип, что и их ввод, или могут возвращать разные типы? – rgettman

+1

Сколько у вас функций, максимум? –

+1

И каков тип, возвращаемый последней функцией? –

ответ

3

Если у вас есть несколько функций (например, если вы можете записать их), то я предлагаю вам не Не добавляйте их в список. Вместо этого составьте их в одну функцию, а затем примените эту единственную функцию к каждому элементу данной коллекции.

Ваш метод multipleMapping() Теперь будет получать одну функцию:

public static <T, R> List<R> multipleMapping(
    Collection<T> collection, Function<T, R> function) { 

    return collection.stream() 
      .map(function) 
      .collect(Collectors.toList()); 
} 

Затем в коде вызова, вы можете создать функцию, состоящую из многих функций (вы будете иметь все функции, во всяком случае) и вызовите multipleMapping() метод с этой функцией.

Например, предположим, что у нас есть список кандидатов:

List<String> candidates = Arrays.asList(
     "Hillary", "Donald", 
     "Bernie", "Ted", "John"); 

И четыре функции:

Function<String, Integer> f1 = String::length; 

Function<Integer, Long> f2 = i -> i * 10_000L; 

Function<Long, LocalDate> f3 = LocalDate::ofEpochDay; 

Function<LocalDate, Integer> f4 = LocalDate::getYear; 

Эти функции могут быть использованы для составления новой функции следующим образом:

Function<String, Integer> function = f1.andThen(f2).andThen(f3).andThen(f4); 

Или также следующим образом:

Function<String, Integer> composed = f4.compose(f3).compose(f2).compose(f1); 

Теперь вы можете вызвать свой метод multipleMapping() со списком кандидатов и наборной function:

List<Integer> scores = multipleMapping(candidates, function); 

Таким образом, мы превратили наш список кандидатов в список счетов, явным образом составляя новую функцию от четырех различных функций и применения этой скомпонованной функции к каждому кандидату.

Если вы хотите знать, кто победит на выборах, вы можете проверить, какой кандидат имеет самый высокий балл, но я дам, что в качестве упражнения для тех, кто заинтересован в политике;)

+0

Функция компоновки выглядит лучше, и она сохранила управление типом. Спасибо @Federico. Ваше решение решает мою проблему. – Artur

8

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

private static <T> List<T> multipleMapping(final Collection<T> collection, final List<Function<T, T>> functions) { 
    Stream<T> stream = collection.stream(); 
    for (Function<T, T> function : functions) { 
     stream = stream.map(function); 
    } 
    return stream.collect(Collectors.toList()); 
} 

Это нормально компилируется: картограф дано map correcly принимает T и возвращает T. Однако, если функции не возвращают тот же тип, что и их ввод, то вы не сможете сохранить безопасность по типу и прибегать к использованию List<Function<Object, Object>>.


Обратите внимание, что мы могли бы использовать UnaryOperator<T> вместо Function<T, T>.

Кроме того, вы можете избежать петли for и свести все функции в один с помощью andThen:

private static <T> List<T> multipleMapping(final Collection<T> collection, final List<Function<T, T>> functions) { 
    return collection.stream() 
        .map(functions.stream().reduce(Function.identity(), Function::andThen)) 
        .collect(Collectors.toList()); 
} 
+0

Да, это нормально. Но у меня разные функции, например: A -> B -> C -> D - not T -> T – Artur

+1

@akfmb Тогда у вас не может быть безопасности типа. Самое лучшее, что вы можете получить, это «Список <Функция <Объект, объект >>», вы хотите быть как можно более общим. Если вам нужна безопасность типа, вы можете сделать это с несколькими перегруженными методами 'multipleMapping (List , Function , Function ' и т. Д. – Tunaki

+1

Вы должны создавать функции вне потока, поэтому вы не создаете их для каждый элемент коллекции –

Смежные вопросы