【问题标题】:What is the fastest way to fill an ArrayList with null in java?在java中用null填充ArrayList的最快方法是什么?
【发布时间】:2021-05-12 14:06:31
【问题描述】:

我想要一个由 n 组整数组成的列表,最初这个列表应该用 null 填充。 很多 Set 稍后会被初始化,有些会保持为空。

我尝试了不同的方法来实现这一点,其中一些包括在这里:

List<HashSet<Integer>> List_of_Sets = Arrays.asList(new HashSet[n]);
ArrayList<HashSet<Integer>> List_of_Sets = new ArrayList<>(n);
while(n-- > 0) List_of_Sets.add(null);

有更快的方法吗?

为了澄清数组的一个例子是 Arrays.fill() 曾经比:

/*
 * initialize a smaller piece of the array and use the System.arraycopy 
 * call to fill in the rest of the array in an expanding binary fashion
 */
public static void bytefill(byte[] array, byte value) {
  int len = array.length;

  if (len > 0){
    array[0] = value;
  }

  //Value of i will be [1, 2, 4, 8, 16, 32, ..., len]
  for (int i = 1; i < len; i += i) {
    System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i);
  }
}

^以上代码来自罗斯·德鲁对Fastest way to set all values of an array?的回答

【问题讨论】:

  • 1) 答案是否定的 (AFAIK)。 2)您应该能够通过基准测试(使用正确的技术!!)检查哪个替代方案最快,但我认为Arrays.asList 版本应该稍微快一些。 3)这是“过早的优化”吗?
  • 最后,如果速度对您来说真的很重要,您可以将ArrayList 替换为数组。这将更快,无论是创建和访问/更新。 (只是在某些情况下不太方便。)据我所知,您不会使用List API 添加和删除列表元素的能力......
  • Collections.fill() 不会在空列表上做任何事情,所以如果您对它感到满意,那就有点令人费解了。有Collections.nCopies() 可以与null 一起使用。
  • 我会 List&lt;HashSet&lt;Integer&gt;&gt; List_of_Sets = Arrays.asList(new HashSet[n]); 继续前进
  • 你也可以写一个native方法。

标签: java performance arraylist


【解决方案1】:

有更快的方法吗?

据我所知,没有。当然,没有比这更快的简单方法了。

根据它的工作原理,我认为(但我没有测试过)Arrays.asList(new HashSet[n]) 应该是最快的解决方案。

可以实现自定义List 实现,它类似于ArrayList,但预初始化为N 个null 值。但在底层初始化将与asList 返回的List 实现中发生的几乎相同。所以我怀疑任何性能改进都会显着......或者值得付出努力。

如果您想确定这一点,您可以编写各种选项的基准。但是,在这种情况下,我认为这不是正确的方法。

相反,我建议您对整个应用程序进行基准测试和分析,以确定此列表上的操作是否是真正的性能热点。

  • 如果它不是热点,我的建议是使用Arrays.asList 方法并将时间花在更重要的事情上。

  • 如果是热点,则应考虑将List 替换为数组。根据您之前的描述,似乎您将使用 List like 一个数组;即使用定位 get 和 set 操作,并且不使用更改列表大小的操作。如果是这种情况,那么使用真正的数组应该更有效。它节省了内存,避免了一定程度的间接性和(可能)一些边界检查。

    不这样做的一个原因是,如果您需要将数组传递给需要List 的其他代码。

【讨论】:

    【解决方案2】:

    如果调整大小对您来说并不重要,那么实现您自己的列表可能会很快。它也可能是越野车。与 Java 的列表相比,基准测试至少会很有趣。您可能会看到一种奇怪的效果,即标准列表可能会更快地被 JIT 优化,因为它们可以被 Java 的标准库在内部使用。

    这是我的尝试,虽然我建议你不要使用它。请改用标准列表实现。

    import java.util.*;
    
    public class FastListOfNullsDemo {
        public static void main(String[] args) {
            Set<Integer>[] arr = new Set[100_000]; // all set to null by default.
            List<Set<Integer>> myList = new ArrayBackedList<>(arr);
            
            myList.set(3, new TreeSet<Integer>());
            
            myList.get(3).add(5);
            myList.get(3).add(4);
            myList.get(3).add(3);
            myList.get(3).add(2);
            myList.get(3).add(1);
            
            // Let's just print some because 100,000 is a lot!
            for (int i = 0; i < 10; i++) {
                System.out.println(myList.get(i));
            }
        }
    }
    
    class ArrayBackedList<T> extends AbstractList<T> {
        private final T[] arr;
        
        ArrayBackedList(T[] arr) {
            this.arr = arr;
        }
        
        @Override
        public T get(int index) {
            return arr[index];
        }
    
        @Override
        public int size() {
            return arr.length;
        }
        
        @Override
        public T set(int index, T value) {
            T result = arr[index];
            arr[index] = value;
            return result;
        }
    }
    

    另一种可能性是实现一个始终为空、大小固定的列表。使用它来初始化 ArrayList。我不能保证它很快,但你可以试试看。

    import java.util.*;
    
    public class FastListOfNullsDemo {
        public static void main(String[] args) {
            List<Set<Integer>> allNull = new NullList<>(100_000);
            List<Set<Integer>> myList = new ArrayList<>(allNull);
            
            myList.set(3, new TreeSet<Integer>());
            
            myList.get(3).add(5);
            myList.get(3).add(4);
            myList.get(3).add(3);
            myList.get(3).add(2);
            myList.get(3).add(1);
            
            System.out.println(myList.size());
            // Let's just print some because 100,000 is a lot!
            for (int i = 0; i < 10; i++) {
                System.out.println(myList.get(i));
            }
        }
    }
    
    class NullList<T> extends AbstractList<T> {
        private int count;
        
        NullList(int count) {
            this.count = count;
        }
        
        @Override
        public T get(int index) {
            return null;
        }
    
        @Override
        public int size() {
            return count;
        }
    }
    

    【讨论】:

    • 谢谢!我最终使用了一个 n HashSet 数组,所以我会按照你的建议而不使用它。为了未来读者的利益,我已将问题编辑得更笼统。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多