【问题标题】:Creating an empty List<String> based on Generics基于泛型创建一个空的 List<String>
【发布时间】:2018-10-13 16:28:50
【问题描述】:

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

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);

【问题讨论】:

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


【解决方案1】:

如果你可以修改你的方法

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

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

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

【讨论】:

  • 工作正常,更干净!
【解决方案2】:

让调用者也传入Supplier&lt;T&gt;

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

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

【讨论】:

    【解决方案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());
        }
    }
    

    【讨论】:

      【解决方案4】:

      您可以通过将List&lt;String&gt; 作为参数传递来通过反射创建类。
      事实上,您不需要为列表指定任何通配符。

      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());
      }
      

      【讨论】:

        【解决方案5】:

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

        请注意,标准 API(List/Collection + Stream)已提供此模式,因此您无需重新创建它。 - 见底部注释。

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

        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())

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-17
          • 2019-06-23
          • 1970-01-01
          • 2023-02-06
          相关资源
          最近更新 更多