基于泛型创建空List <string>

时间:2018-05-03 11:12:52

标签: java collections java-8 functional-programming predicate

所以我目前正在尝试实现一种方法,该方法对列表进行一些过滤,而不管它们的实际类型如何。这是实际的方法:

public static <T extends List<String>> T filterList(T list, Predicate <String> predicate) {

    T newList = ???
    list.forEach(s -> {
        if (predicate.test(s)) newList.add(s);
    });
    return newList;

}

因此泛型类型T基本上是List的一些实现,例如ArrayList或LinkedList,不管它们的实际实现如何,我想通过作为参数传递的Predicate进行一些过滤。该方法的返回类型与作为参数传递的列表相同。但是如何基于T实现空列表是可能的(见第2行)? 为了向您展示如何使用该方法,我提供了一个示例。以下示例将根据包含的字符串的长度过滤ArrayList:

ArrayList<String> listOfNames = new ArrayList<>();
listOfNames.add("stackoverflowuser");
listOfNames.add("sitaguptana");
listOfNames.add("nyan cat");
listOfNames.add("pedro");

Predicate<String> lengthUnderTen = (string) -> string.length() < 10;

ArrayList <String> result = filterList(listOfNames,lengthUnderTen);

5 个答案:

答案 0 :(得分:3)

如果我正确理解你的问题,那么我不明白为什么你需要在这里使用泛型。

以下函数将接受任何将List扩展为参数的类,例如一个ArrayList,LinkedList等:

public static List<String> filterList(List<String> list, Predicate<String> predicate) {
    return list.stream().filter(predicate).collect(Collectors.toList());
}

完整示例:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Example {

    public static void main(String[] args) {
        ArrayList<String> example1 = new ArrayList<>();
        example1.add("abc");
        example1.add("ghe");

        LinkedList<String> example2 = new LinkedList<>();
        example2.add("foo");
        example2.add("bar");

        List<String> result1 = filterList(example1, s -> s.contains("a"));
        List<String> result2 = filterList(example2, s -> s.contains("f"));
    }

    public static List<String> filterList(List<String> list, Predicate<String> predicate) {
        return list.stream().filter(predicate).collect(Collectors.toList());
    }
}

答案 1 :(得分:1)

如果您可以将方法修改为

public static <T> List<T> filterList(List<T> list, Predicate<T> predicate) {

    return list.stream().filter(predicate).collect(Collectors.toList());
}

它看起来很干净,因为它适用于任何类型的List,不仅适用于List&lt; String&gt;。这种方法会更通用。

答案 2 :(得分:1)

呼叫者也可以通过Supplier<T>

public static <T extends List<String>> T filterList(T list, Predicate <String> predicate, Supplier<T> listCreator) {

    T newList = listCreator.get();
    list.forEach(s -> {
       // ...

答案 3 :(得分:0)

您可以通过传递List<String>作为参数来反射创建类 实际上,您不需要为列表指定任何通配符。

public static List<String> filterList(List<String> list,  Predicate<String> predicate) throws InstantiationException, IllegalAccessException {

    List<String> newList = list.getClass()
                               .newInstance();
    list.forEach(s -> {
        if (predicate.test(s)) newList.add(s);
    });
    return  newList;
}

但请注意,如果实施并不重要,那么更简洁的方法是使用流来收集新的List:

public static List<String> filterList(List<String> list,  Predicate<String> predicate) throws InstantiationException, IllegalAccessException {

  return list.stream()
             .filter(predicate)
             .collect(Collectors.toList());
}

答案 4 :(得分:0)

你有一个基类,它已经允许你干净地编程接口。您可以设计此API方法以返回List对象,将泛型类型保留在元素级别。

请注意,此模式已由标准API(列表/集合+流)提供,因此您不需要重新创建它。 - 见底部的注释。

如果对方法返回的列表类型没有任何限制,那么它的实现选择它返回的列表类型(使用下面的数组列表) ):

public static <T> List<T> filterList(List<T> list, Predicate<T> predicate) {

    List<T> newList = new ArrayList<>(); //You can choose a different type here
    list.forEach(s -> {
        if (predicate.test(s)) newList.add(s);
    });

    return newList;
}

如果您将其留给调用者选择创建了哪种类型的列表,那么您可能应该选择工厂:

public static <U, T extends List<U>> T filterList(T list, 
      Predicate<U> predicate, Supplier<T> newListFactory) {

    T newList = newListFactory.get(); //You can choose a different type here
    list.forEach(s -> {
        if (predicate.test(s))
            newList.add(s);
    });

    return newList;
}

注意:此模式已由集合API提供:

java.util.stream.Stream.filter(Predicate<? super T>)

这允许你做同样的事情,除了创建返回的列表(比如,你运行collect(Collectors.toList())