将 Set<T> 转换为 List<T> 的最简洁方法

Posted

技术标签:

【中文标题】将 Set<T> 转换为 List<T> 的最简洁方法【英文标题】:Most concise way to convert a Set<T> to a List<T> 【发布时间】:2011-01-20 03:27:32 【问题描述】:

例如,我目前正在这样做:

Set<String> setOfTopicAuthors = ....

List<String> list = Arrays.asList( 
    setOfTopicAuthors.toArray( new String[0] ) );

你能打败这个吗?

【问题讨论】:

使用java.util.Collection: O(0) @Carl,我必须将 Set 提交到需要列表的第 3 方界面。 @Tim 我希望我可以将第 3 方界面更改为使用 Collection。 我明白了;除非有任何奇怪的限制,否则我会接受罗杰的回答。不过,除非您实际上再次使用 List,否则我会跳过将其分配给任何东西(即,使用 foo.api(new ArrayList(listOfTopicAuthors)) 而不是 foo.api(list))。 @JacquesRenéMesrine:有问题的第一行代码具有误导性:预期:Set&lt;String&gt; setOfTopicAuthors = .... 实际:Set&lt;String&gt; listOfTopicAuthors = .... 或者另一种方法可以是List&lt;String&gt; list = Arrays.asList(setOfTopicAuthors.toArray(String[]::new)),在链接的答案中有详细说明。 【参考方案1】:
List<String> list = new ArrayList<String>(listOfTopicAuthors);

【讨论】:

... 从而彻底违反 Java 代码约定:oracle.com/technetwork/java/javase/documentation/…! :) :) 在此之后,当我尝试访问列表元素时,它给了我错误,“java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String” ..don;t know为什么......它很简单 list.get(int) 就是这样......有什么建议吗? 我相信在 Java 7 及以上版本中你可以将类型参数省略为 ArrayList yielding: List&lt;String&gt; l = new ArrayList&lt;&gt;(listOfTopicAuthors); 最简洁不使用外部库? 如果listOfTopicAuthors为空,它会抛出NullPointerException。【参考方案2】:
List<String> l = new ArrayList<String>(listOfTopicAuthors);

【讨论】:

在与接受的答案相同的分钟内回答并且没有获得信任。 +1 @Adamski 我最终得到了一个索引从 1 而不是 0 开始的列表,有什么补救措施吗? @Jack:绝对不会这样。来自 java.util.List 的 Javadoc:“列表(如 Java 数组)是从零开始的。” @Adamski 感谢您的回复。我知道列表应该并且是基于零的,这就是为什么这对我来说如此奇怪。将我的集合转换为列表后,我无法对其执行任何迭代操作 foreach、排序等。我得到一个 NullPointerException,但是当我期望我的列表没有任何元素为空时,我注意到的唯一奇怪的是索引从 1 开始。但是,如果我只是创建一个普通列表,则索引从 0 开始。奇怪吗? @Jack:这听起来很奇怪。如果您将代码作为单独的问题发布,我相信有人可以帮助您。【参考方案3】:

考虑到我们有Set&lt;String&gt; stringSet,我们可以使用以下内容:

纯 Java

List<String> strList = new ArrayList<>(stringSet);

番石榴

List<String> strList = Lists.newArrayList(stringSet);

Apache Commons

List<String> strList = new ArrayList<>();
CollectionUtils.addAll(strList, stringSet);

Java 10(不可修改列表)

List<String> strList = List.copyOf(stringSet);
List<String> strList = stringSet.stream().collect(Collectors.toUnmodifiableList());

Java 8(可修改列表)

import static java.util.stream.Collectors.*;
List<String> stringList1 = stringSet.stream().collect(toList());

按照doc的方法toList()

不保证类型、可变性、可序列化或 返回列表的线程安全;如果对退货有更多的控制权 列表是必需的,使用 toCollection(Supplier)。

因此,如果我们需要特定的实现,例如ArrayList我们可以这样搞定:

List<String> stringList2 = stringSet.stream().
                              collect(toCollection(ArrayList::new));

Java 8(不可修改的列表)

我们可以利用Collections::unmodifiableList 方法包装前面例子中返回的列表。我们也可以编写自己的自定义方法:

class ImmutableCollector 
    public static <T> Collector<T, List<T>, List<T>> toImmutableList(Supplier<List<T>> supplier) 
            return Collector.of( supplier, List::add, (left, right) -> 
                        left.addAll(right);
                        return left;
                    , Collections::unmodifiableList);
        

然后将其用作:

List<String> stringList3 = stringSet.stream()
             .collect(ImmutableCollector.toImmutableList(ArrayList::new)); 

另一种可能性是使用collectingAndThen 方法,该方法允许在返回结果之前进行一些最终转换:

    List<String> stringList4 = stringSet.stream().collect(collectingAndThen(
      toCollection(ArrayList::new),Collections::unmodifiableList));

需要注意的一点是,Collections::unmodifiableList 方法根据doc 返回指定列表的不可修改视图。不可修改的视图集合是不可修改的集合,也是支持集合的视图。请注意,对支持集合的更改可能仍然是可能的,并且如果发生更改,它们将通过不可修改的视图可见。但是收集器方法 Collectors.unmodifiableListJava 10 中返回真正不可变的列表。

【讨论】:

我用它来将Set&lt;Double&gt; 转换为List&lt;Double,其中集合来自LinkedHashMap.keySet() 方法。 Eclipse 告诉我存在类型不匹配,并且我无法从 Object 转换为 List&lt;Double&gt;。你能告诉我为什么会发生这种情况吗?我通过强制转换解决了这个问题,但我想知道为什么会这样。 是的,既然Java开发者应该使用越来越多的Java 8特性,这个答案比上面2个答案要好。【参考方案4】:

试试这个Set:

Set<String> listOfTopicAuthors = .....
List<String> setList = new ArrayList<String>(listOfTopicAuthors); 

试试这个Map:

Map<String, String> listOfTopicAuthors = .....
// List of values:
List<String> mapValueList = new ArrayList<String>(listOfTopicAuthors.values());
// List of keys:
List<String> mapKeyList = new ArrayList<String>(listOfTopicAuthors.KeySet());

【讨论】:

【参考方案5】:

如果您使用 Guava,则从 Lists 类静态导入 newArrayList 方法:

List<String> l = newArrayList(setOfAuthors);

【讨论】:

【参考方案6】:

不太确定您通过代码的上下文到底在做什么,但是...

为什么要设置listOfTopicAuthors 变量?

List<String> list = Arrays.asList((....).toArray( new String[0] ) );

“....”代表您的系列如何发挥作用,无论它是新的还是来自其他位置。

【讨论】:

以上是关于将 Set<T> 转换为 List<T> 的最简洁方法的主要内容,如果未能解决你的问题,请参考以下文章

如何将通用 List<T> 转换为基于接口的 List<T>

Java 流:将 List<T> 转换为 List<List<T>>

将 IEnumerable<T> 转换为 List<T>

将 DataTable 转换为 List<T>

将 DataTable 转换为 List<T>

如何将 List 转换为从 List<T> 继承的类型?