Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么Intellij Idea建议在使用循环将数组转换为集合时创建中间列表?_Java_Intellij Idea_Collections - Fatal编程技术网

Java 为什么Intellij Idea建议在使用循环将数组转换为集合时创建中间列表?

Java 为什么Intellij Idea建议在使用循环将数组转换为集合时创建中间列表?,java,intellij-idea,collections,Java,Intellij Idea,Collections,假设我有以下代码: public Set<String> csvToSet(String src) { String[] splitted = src.split(","); Set<String> result = new HashSet<>(splitted.length); for (String s : splitted) { result.add(s); } return result; }

假设我有以下代码:

public Set<String> csvToSet(String src) {
    String[] splitted = src.split(",");
    Set<String> result = new HashSet<>(splitted.length);
    for (String s : splitted) {
        result.add(s);
    }
    return result;
}
完整的检查信息是:

当调用循环中的某个方法(例如collection.add(x))时,此检查会发出警告。当调用批量方法(例如collection.addAll(listOfX))时,该方法可能会被替换。 如果选中复选框“Use Arrays.asList()to wrap Arrays”,则即使原始代码在bulk方法需要集合时迭代数组,检查也会发出警告。在这种情况下,快速修复操作将自动使用Arrays.asList()调用包装数组

从检查说明来看,它听起来像预期的那样工作

如果我们参考关于将数组转换为集合()的问题的顶部答案,建议使用相同的一行:

Set<T> mySet = new HashSet<T>(Arrays.asList(someArray));
Set mySet=newhashset(Arrays.asList(someArray));
即使从数组创建ArrayList是O(1),我也不喜欢创建额外的List对象

通常我相信Intellij检查,并假设它不会提供任何效率更低的东西。 但今天我很好奇为什么:top SO answer和Intellij Idea(默认设置)都建议使用相同的一行程序来创建无用的中间列表对象,同时还有一个
Collections.addAll(destCollection,yourray)
自JDK 6以来


我看到的唯一原因是(检查和答案)都太旧了。如果是这样,下面是改进intellij idea的原因,并对提议集合的答案进行更多投票。
Collections.addAll()
:)

关于intellij为什么不建议使用数组的提示

Set<String> result = new HashSet<>(splitted.length);
result.addAll(Arrays.asList(splitted));
return result;
请注意,集合的容量不是
c
的大小

因此,这种变化在语义上并不等同



不要担心创建
列表
。它真的很便宜。它不是免费的;但是您必须在一个真正的性能关键循环中使用它才能注意到。

我编写了一个小函数来测量将数组添加到哈希集的三种方法的性能,下面是结果

首先,它们使用的基本代码将生成一个
maxSize
数组,其值介于
0-100

    int maxSize = 10000000; // 10M values
    String[] s = new String[maxSize];
    Random r = new Random();

    for (int i = 0; i < maxSize; i++) {
        s[i] = "" + r.nextInt(100);
    }
因此,第一种方法是将代码与循环一起使用,对于
10M值
,它需要
150ms到190ms之间的时间(我为每个方法运行了几次基准测试)

第三种方法是使用
Collections.addAll(result,s)并且时间介于
170ms和200ms之间

        Main.benchmark("result.addAll(Arrays.asList(s)): ", () -> {
            Set<String> result = new HashSet<>(s.length);
            result.addAll(Arrays.asList(s));
        });
    Main.benchmark("Collections.addAll(result, s); ", () -> {
        Set<String> result = new HashSet<>(s.length);
        Collections.addAll(result, s);
    });
除此之外,所有的
addAll
方法都将与您所做的完全相同,一个
for循环

// addAll method for Collections.addAll(result, s);
public static <T> boolean addAll(Collection<? super T> c, T... elements) {
    boolean result = false;
    for (T element : elements)
        result |= c.add(element);
    return result;
}

// addAll method for result.addAll(Arrays.asList(s));
public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}
//集合的addAll方法。addAll(结果,s);

public static boolean addAll(collection)您要求什么?哪一个最好?第三个。@AndyTurner哪一个最好,其中best=最高性能?使用
asList(array)
只是围绕数组包装一些方便的行为;这样做允许您使用
HashSet
构造函数,这样您就可以一步创建集合并填充它。我不明白为什么会有任何性能下降。@Derp最好,因为它是最简洁的,并且是创建该列表的性能影响-如果有的话根本不值得担心。尝试不创建列表是(可能没有根据的)微优化。这里经常重复的建议是:编写可读性最高的代码;如果您发现性能不足,请分析它,只有当您发现这是瓶颈时,才应该担心重写它。@khelwood with for,没有对迭代器方法的调用,因此使用的委托较少,因此可能会有一些编译器循环optim在原始代码(即软件管道)中,Izization工作得更好。我认为Intellijt做得不好。这个包装很便宜,除非您以非常敏感的性能方式使用它。哎哟:-)看起来我真的需要更多的睡眠!:-)这个答案表明,当OP尝试过早优化时,他们反而悲观了。HashSet构造函数参数的值不正确,最终创建的HashSet太小,更可能导致冲突。API开发人员更了解如何以最佳方式初始化哈希集以保存给定集合,因此要充分利用他们的知识。另外,通过重用一种常用的API方法,您更有可能对其进行JIT编译。答案很有趣,但我有点离题了@KlitosKyriacou I并没有以任何方式使用构造函数。有人建议我使用Set实例的
addAll
,它需要collection作为参数,而有一个静态方法
Collections.addAll(yourDestCollection,yourscarr)
@KlitosKyriacou Close。不正确的初始大小确实太小,但结果不会导致更多碰撞。取而代之的是,必须在添加元素的过程中重新分配表。但是,使用
HashSet(Collection)
构造函数可能是最好的方法。
System.currentTimeMillis()
不是单调的。改为使用
System.nanoTime()
(或JMH)。@KlitosKyriacou每次运行100次迭代的平均值后:有趣的结果。看起来显式循环毕竟是最快的。考虑HashSet构造函数参数,在这个特定的测试用例中,数组大小的值不是太低。事实上,它太高了!您正在添加1000万个元素,但它们是0到99之间的随机数。因此,绝大多数都是重复的,哈希集最多只有100个元素。@KlitosKyriacou我怀疑循环技术是否会产生显著的差异。答案中列出的初始基准运行的高差异告诉我,很难从任何结果中得出结论。需要更精确的基准测试方法。
    Main.benchmark("Normal loop ", () -> {
        Set<String> result = new HashSet<>(s.length);
        for (String a : s) {
            result.add(a);
        }
    });
        Main.benchmark("result.addAll(Arrays.asList(s)): ", () -> {
            Set<String> result = new HashSet<>(s.length);
            result.addAll(Arrays.asList(s));
        });
    Main.benchmark("Collections.addAll(result, s); ", () -> {
        Set<String> result = new HashSet<>(s.length);
        Collections.addAll(result, s);
    });
    private final E[] a;

    ArrayList(E[] array) {
        a = Objects.requireNonNull(array);
    }
// addAll method for Collections.addAll(result, s);
public static <T> boolean addAll(Collection<? super T> c, T... elements) {
    boolean result = false;
    for (T element : elements)
        result |= c.add(element);
    return result;
}

// addAll method for result.addAll(Arrays.asList(s));
public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}