简体   繁体   English

Java ArrayList添加当前大小以外的项目

[英]Java ArrayList add item outside current size

Wondering whether there is an efficient way to add an item to Java's ArrayList at a bigger position than its current size: 想知道是否有一种有效的方法将项目添加到Java的ArrayList中,其位置比当前大小更大:

Scenario: 场景:

   ArrayList<Item> items = new ArrayList<Item>;
   ... let's say I add three elements

Now I would like to add an item at position 10 (leaving items from 3 to 10 to null) 现在我想在位置10添加一个项目(将项目从3到10保留为null)

  items.add(10,newItem);  // item.size() == 3 

Is there an efficient way resizing/filling an ArrayList with nulls? 是否有一种有效的方法可以使用null调整/填充ArrayList?

Java's implementation makes size field private :-(.. Java的实现使大小字段私有:-( ..

你可以做的最好的事情是items.addAll(Collections.nCopies(6, null))并希望,ArrayList实现了一些内部紧固的行为

How about this? 这个怎么样?

ArrayList<Item> items = new ArrayList<Item>();

items.add(new Item(0));
items.add(new Item(1));
items.add(new Item(2));

items.addAll(Collections.<Item>nCopies(7, null));
items.add(10,new Item(10));

System.out.println(items);

prints 版画

[0, 1, 2, null, null, null, null, null, null, null, 10]

This is an older question, but you can now use SparseArray as an (almost) direct drop-in replacement for ArrayList . 这是一个较旧的问题,但您现在可以使用SparseArray作为ArrayList的(几乎)直接替代品。 It allows non-contiguous integer key values, and returns null if a value has not been set for a key. 它允许非连续的整数键值,如果没有为键设置值,则返回null。 Performance-wise it was designed exactly for your needs. 性能方面,它的设计完全符合您的需求。 Instead of add you use append , which is more descriptive in that you are appending to the end of whatever the max key is, even if there is gaps. 而不是add你使用append ,这更具描述性,因为即使存在间隙,你也会附加到max key的末尾。 You can also set at any key value you'd like, even if it is beyond the maximum key. 您也可以set任何您想要的键值,即使它超出了最大键值。

Use TreeMap instead. 请改用TreeMap。 Here is simple example to check memony consuption. 这是检查和谐消耗的简单例子。 Run first and second test separatly and use jvisualvm to check heap size. 分别运行第一个和第二个测试并使用jvisualvm检查堆大小。 Remember to Perform GC several times. 请记住多次执行GC。

    public class Test {


            public static void main(String[] args) throws InterruptedException {
                String s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque metus.";


                //Test 1
                ArrayList<String> l = new ArrayList<String>();

                for (int i = 0; i < 1000000; i++) {
                    l.add(s + " " + i);
                    l.addAll(Collections.nCopies(i % 10, (String)null)); //Add some nulls
                }
                //Heap is > 5MB

                //Test 2 uncomment and comment test 1
    //          SortedMap<Integer, String> map = new TreeMap<Integer, String>();
    //          for (int i = 0; i < 1000000; i++) {
    //              map.put(i,s + " " + i);
    //          }
                //Heap is < 5MB

                Thread.sleep(100000);

            }
    }

It looks like TreeMap version is even less memory consuming than ArrayList version. 看起来TreeMap版本比ArrayList版本的内存消耗更少。 Check yourself. 自行检查。

No, you can't: 不,你不能:

http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(int , E) http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(int,E

Throws: IndexOutOfBoundsException - if the index is out of range (index < 0 || index > size()) 抛出:IndexOutOfBoundsException - 如果索引超出范围(索引<0 || index> size())

I would consider using a SortedMap instead of a List here. 我会考虑在这里使用SortedMap而不是List。 This will allow for indexes to not exist: 这将允许索引不存在:

SorteMap<Integer, Item> myMap = new TreeMap<Integer, Map>();
int i=0;
myMap.put(i++, first);
myMap.put(i++, second);
myMap.put(i++, third);
myMap.put(10, other);

If a Map truly will not work, as you stated. 如果你说的话,地图真的不起作用。 I would then suggest creating a Decorator around ArrayList. 然后我会建议在ArrayList周围创建一个Decorator。 In the insert method, add nulls to fill the empty locations. 在insert方法中,添加空值以填充空位置。 I would suggest using Guava's ForwardingList to ease the creation of the class. 我建议使用Guava的ForwardingList来简化类的创建。 This way you would only have to implement one method. 这样你只需要实现一个方法。

No, you can't do this, But if you wish to do that, then add empty object in remaining index such as.. 不,你不能这样做,但如果你想这样做,那么在剩余的索引中添加空对象,比如..

    ArrayList<Object> items = new ArrayList<Object>();
    items.add(new Object());
    items.add(new Object());
    items.add(new Object());
    items.add(3,new Object());

If memory and index is so important that use a normal array. 如果内存和索引非常重要,那么使用普通数组。

When it becomes to small use System.arraycopy thats the way ArrayList does it internal. 当它变得很小时使用System.arraycopy就像ArrayList在内部做的那样。

-- -

Even if you use the ArrayList and have a Million Objects it is advisable to use the ArrayList(int initialCapacity)-Constructor to avoid a lot of copy-operations 即使你使用ArrayList并拥有一个Million Objects,建议使用ArrayList(int initialCapacity)-Constructor来避免大量的复制操作

@icCube- you said, that list should be about 90% full. @ icCube-你说,那个名单应该是90%左右。 My idea for this solution is: 我对这个解决方案的想法是:

  • If you exactly know target size - use plain array 如果你确切知道目标大小 - 使用普通数组
  • If you are aware of target size - use ArrayList with initial capacity as close as possible to target size. 如果您了解目标大小 - 请使用ArrayList,其初始容量尽可能接近目标大小。 Put nulls with l.addAll(Collections.nCopies(n, (String)null)); 将空值与l.addAll(Collections.nCopies(n, (String)null));放在一起l.addAll(Collections.nCopies(n, (String)null)); as people said. 正如人们所言。
  • If you don't know target size - your ArrayList will be resized many times. 如果您不知道目标大小 - 您的ArrayList将重复调整多次。 Resizing means copying whole underlying array (it uses Arrays.copyOf). 调整大小意味着复制整个底层数组(它使用Arrays.copyOf)。 You can imagine what happens if array is copied around - GC has lots of work. 你可以想象如果复制数组会发生什么 - GC有很多工作要做。 Use TreeMap then. 然后使用TreeMap。

Use constructor ArrayList(int initialCapacity) . 使用构造函数ArrayList(int initialCapacity) This way you can set an initial capacity. 这样您就可以设置初始容量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM