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

213

例如,我目前正在做这件事:

Set<String> setOfTopicAuthors = ....

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

你能打败这个吗?


2
使用 java.util.Collection:O(1) - Tim
@Carl,我必须将Set提交到需要List的第三方界面。@Tim我希望我可以更改第三方接口以使用Collection。 - Jacques René Mesrine
1
我明白了,除非有奇怪的限制,否则我会选择Roger的答案。不过,除非你真的再次使用List,否则我会跳过将其分配给任何东西(即使用foo.api(new ArrayList<String>(listOfTopicAuthors))而不是foo.api(list))。 - Carl
2
@JacquesRenéMesrine: 问题中的第一行代码有误导性: 期望:Set<String> setOfTopicAuthors = .... 实际:Set<String> listOfTopicAuthors = .... - realPK
或者另一种实现方式是List<String> list = Arrays.asList(setOfTopicAuthors.toArray(String[]::new)),详见链接中的答案。 - Naman
Java 8和Java 10解决方案:https://dev59.com/EXE95IYBdhLWcg3watQ3#32179585 - akhil_mittal
6个回答

453
List<String> list = new ArrayList<String>(listOfTopicAuthors);

1
...从而彻底违反了Java代码规范:http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-135099.html!:) :) - Håvard Geithus
在这之后,当我尝试访问列表元素时,它会给出错误提示:"java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String"。不知道为什么,只是简单的list.get(int)而已...有什么建议吗? - CoDe
2
我相信在Java 7及以上版本中,您可以省略ArrayList的类型参数,从而产生以下结果:```List l = new ArrayList<>(listOfTopicAuthors);```最简洁的方法是不使用外部库吗? - Brett Duncavage
如果listOfTopicAuthors为空,它将抛出NullPointerException。 - w35l3y

94
List<String> l = new ArrayList<String>(listOfTopicAuthors);

6
为了在同一分钟内回答并且不得到信用点的问题,+1。 翻译:为了在一分钟内与被接受的答案相同的时间内回答问题但不获得信用点,需要加1。 - jayeffkay
@Adamski,我最终得到的列表索引从1开始而不是0,有什么解决方法吗? - Jack
1
@Jack:绝对不会这样。从java.util.List的Javadoc中可以看到:“列表(如Java数组)是从零开始的。” - Adamski
@Adamski 感谢您的回复。我知道列表应该是从零开始的,这就是为什么这对我来说很奇怪的原因。将我的集合转换为列表后,我无法对其执行任何迭代操作,例如foreach、sort等。我会收到一个NullPointerException,但是当我检查我的列表时,没有任何元素为空,唯一奇怪的是索引从1开始。然而,如果我只创建一个普通的列表,索引就从0开始。很奇怪吧? - Jack
1
@Jack:听起来很奇怪。如果你将你的代码作为一个单独的问题发布,我相信会有人能够帮助你解决问题。 - Adamski

25

考虑到我们有Set<String> 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());

根据文档中的toList()方法,返回的List类型、可变性、可串行化性或线程安全性均不做保证;如果需要更多控制返回的List,可以使用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<Double> 转换为 List<Double>,其中的 set 是从 LinkedHashMap.keySet() 方法中获取的。Eclipse 告诉我存在类型不匹配的问题,无法将 Object 转换为 List<Double>。您能告诉我为什么会出现这种情况吗?我通过强制转换来解决了这个问题,但我想知道它为什么会发生。 - Ungeheuer
1
是的,因为Java开发人员应该使用更多的Java 8功能,所以这个答案比上面的两个答案更好。 - Shubham Pandey

14

尝试使用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());

2
如果您正在使用Guava,您可以从Lists类中静态导入newArrayList方法:
List<String> l = newArrayList(setOfAuthors);

0

我不太确定你在代码上下文中究竟在做什么,但...

为什么要创建listOfTopicAuthors变量呢?

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

"...." 代表你的设置是如何发挥作用的,无论它是新的还是来自其他位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接