<String> 基于泛型创建空列表



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

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,无论它们的实际实现如何,我都想通过作为参数传递的谓词进行一些过滤。该方法的返回类型与作为参数传递的列表相同。但是,如何基于 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);

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

以下函数将接受任何将 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());
}
}

如果你可以将你的方法修改为

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

它看起来很干净,因为它适用于任何类型的列表,而不仅仅是 List。此方法将更加通用。

让调用方也通过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 -> {
// ...

你有一个基类,它已经允许你干净地编程到接口。可以将此 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())(

您可以通过将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;
}

但请注意,如果实现无关紧要,一种更干净的方法是使用流来收集新列表:

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

最新更新