如何将Stream操作参数添加到我的函数中?

时间:2016-11-21 17:30:00

标签: methods java-8 java-stream

我有一个函数可以在List上执行一些流操作(特别是过滤器)。

public List<String> getAndFilterNames(List<Person> people, Predicate<Person> nameFilter){
  List<String> allNames = people.stream()
    .map(person -> person.getName())
    .filter(nameFilter)
    .collect(Collectors.toList());
  return allNames;
}

我希望能够传递中间流操作(filterdistinct等)并让我的函数在运行终端操作之前执行该操作。类似的东西:

public List<String> getAndProcessNames(List<Person> people, <intermediate stream operation>){
  List<String> allNames = people.stream()
    .map(person -> person.getName())
    // perform <intermediate stream operation> here
    .collect(Collectors.toList());
  return allNames;
}

尽管如此,根据我目前的经验水平,这似乎是不可能的。某些中间操作具有参数(如filter),而其他参数则不具有(distinct),因此我无法设置单个参数类型来处理所有情况。 ..我想我可以使用FunctionSupplier创建几个签名。

即使这样,带参数的函数所需的函数接口也会有所不同...... filter需要Predicatemap需要Function,而且根据我的理解,没有办法表示通用的功能接口。那是对的吗?它们都没有实际的公共类或接口。

所以,最后,似乎我最好的选择只是mapcollect,然后根据具体情况运行我想要的流操作,如:

public List<String> getNames(List<Person> people){
  List<String> allNames = people.stream()
    .map(person -> person.getName())
    .collect(Collectors.toList());
  return allNames;
}

List<Person> employees = // a bunch of people
List<String> employeeNames = getNames(employees);
employeeNames = employeeNames.stream(). // desired operations

编辑:或者,根据@Holger:

public Stream<String> getNamesStream(List<Person> people){
  Stream<String> namesStream = people.stream()
    .map(person -> person.getName());
  return namesStream;
}

List<Person> employees = // a bunch of people
Stream<String> employeeNamesStream = getNamesStream(employees);
employeeNamesStream(). // desired operations

或者我有什么遗失的东西?

2 个答案:

答案 0 :(得分:11)

您想要的是从{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:GetBucketLocation" ], "Resource": [ "arn:aws:s3:::*" ] }, { "Effect": "Allow", "Action": "s3:GetObject", "Resource": [ "arn:aws:s3:::YOURBUCKETNAME", "arn:aws:s3:::YOURBUCKETNAME/*" ] } ] } Stream的功能。例如:

Stream

然后调用:

public List<String> processNames(Function<Stream<String>, Stream<String>> f) {
    return f.apply(people.stream().map(Person::getName))
            .collect(toList());
}

答案 1 :(得分:0)

是的,你是对的。中间操作没有扩展的公共基接口,但由于它们实际执行的操作不同,也不应该有。

可以创建一些可以链接这些调用的方法:

private static <T> Stream<T> applyPredicates(Stream<T> input, List<Predicate<T>> predicates) {
    Stream<T> result = Stream.concat(input, Stream.empty());
    for (Predicate<T> pred : predicates) {
          result = result.filter(pred);
    }
    return result;
}

/**
  * this could be modified to accept more then one parameters
  */
private static <T, R> Stream<R> applyFunction(Stream<T> input, Function<T, R> function) {
     return input.map(function);
}

然后例如:

  List<String> list = Arrays.asList("one", "two", null, "three");

  Predicate<String> p1 = t -> t != null;
  Predicate<String> p2 = t -> t.startsWith("t");

  applyFunction(applyPredicates(list.stream(), Arrays.asList(p1, p2)), String::length)
            .collect(Collectors.toList());

请注意,必须重载applyFunctions以将多个函数作为输入参数,因为每个映射操作可能会将流从T更改为R然后更改为Y,依此类推。