I have an ArrayList, which includes a number of items I want to remove. I have the ids of the items to remove stored in another list. Figured the following code should work trivially, but for some reason, the remove() calls are returning a false value:
ArrayList<Integer> toRemove = new ArrayList<Integer>();
ArrayList<JCheckBox> al = new ArrayList<JCheckBox>();
/* Code that adds a bunch of items to al, and a few integers to toRemove */
System.out.println("Size before removing: " + al.size());
for (int i = toRemove.size() - 1; i >= 0; i--) {
System.out.println("Removing id: " + toRemove.get(i) + ": ");
System.out.println(al.get(toRemove.get(i)));
System.out.println(al.remove(toRemove.get(i)));
}
System.out.println("Size after removing: " + al.size());
I'd get it if the get() call also returned a false value, but it does actually return the object in question. What am I missing here?
The output of the code above:
Size before removing: 3
Removing id: 2:
javax.swing.JCheckBox[...]
false
Size after removing: 3
My guess is you are having a problem with the fact that remove() is overloaded with both int and Object, while get() only takes an int. Try remove(toRemove.get(i).intValue()).
remove(Object) from AbstractCollection will search through the list and remove the given object, which won't be there because you are sending it an Integer and the list only has JCheckBoxs. You are trying to call remove(int), but because you are giving it an Integer, the Object overload is called instead. By converting the Integer to an int, you avoid this problem
Also, can you always be sure the Id in toRemove always equals the index? If toRemove is not in greatest to least order, it won't be.
There are two problems with your code.
First, the wrong "toRemove" method is getting invoked. When you call "toRemove.get(i)", the return value is autoboxed into a java.lang.Integer, instead of an int. Therefore, java.util.List#remove(Object) is called instead of java.util.List#remove(int). It's trying to remove an Integer object, and returns false.
If you cast the Integer to an int, the desired method will get invoked.
Second problem: each time you remove an element of the list, the indexes of all subsequent elements change, as those elements are "shifted" down. There are several ways to get around this. One is to sort your list of indexes in descending order. Another would be to use a set of indexes, create a new array, and copy into the new array only those elements whose index is not in the set.
javax.swing.JCheckBox[...]?
Also, try remove elements by Objects value, like here:
http://www.easywayserver.com/blog/java-remove-element-in-arraylist/
Related
I need to remove only one occurence of an integer in a ArrayList of integers. My code right now removes all integers with a specific value.
list.removeIf(s -> s.equals(data));
If I have for example:
ArrayList<Integer> i = new ArrayList<Integer>();
i.add(1);
i.add(1);
i.add(3);
i.add(5);
and I want to remove only the first 1 or the second 1. Not both.
Solution
Use the List#remove method. That is exactly what it was made for, from the documentation:
Removes the first occurrence of the specified element from this list, if it is present (optional operation). If this list does not contain the element, it is unchanged. [...]
boolean wasRemoved = list.remove(data);
Removing ints
However, you might have a minor issue here. Your data type is Integer and data is probably of type int. And there is already a method with the signature List#remove(int) (documentation) which will remove the element at the given index, not the element itself.
You can bypass this by explicitly boxing your data to an Integer, which is what you actually have stored in the list:
boolean wasRemoved = list.remove((Integer) data);
Or directly make the data variable of type Integer instead of int.
Just use remove method from the list.remove(new Integer(data)), by the implementation you can see that it removes the first element then exits:
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
Here's a nice pitfall I just encountered.
Consider a list of integers:
List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);
Any educated guess on what happens when you execute list.remove(1)? What about list.remove(new Integer(1))? This can cause some nasty bugs.
What is the proper way to differentiate between remove(int index), which removes an element from given index and remove(Object o), which removes an element by reference, when dealing with lists of integers?
The main point to consider here is the one #Nikita mentioned - exact parameter matching takes precedence over auto-boxing.
Java always calls the method that best suits your argument. Auto boxing and implicit upcasting is only performed if there's no method which can be called without casting / auto boxing.
The List interface specifies two remove methods (please note the naming of the arguments):
remove(Object o)
remove(int index)
That means that list.remove(1) removes the object at position 1 and remove(new Integer(1)) removes the first occurrence of the specified element from this list.
You can use casting
list.remove((int) n);
and
list.remove((Integer) n);
It doesn't matter if n is an int or Integer, the method will always call the one you expect.
Using (Integer) n or Integer.valueOf(n) is more efficient than new Integer(n) as the first two can use the Integer cache, whereas the later will always create an object.
I don't know about 'proper' way, but the way you suggested works just fine:
list.remove(int_parameter);
removes element at given position and
list.remove(Integer_parameter);
removes given object from the list.
It's because VM at first attempts to find method declared with exactly the same parameter type and only then tries autoboxing.
list.remove(4) is an exact match of list.remove(int index), so it will be called. If you want to call list.remove(Object) do the following: list.remove((Integer)4).
Any educated guess on what happens when you execute list.remove(1)? What about list.remove(new Integer(1))?
There is no need to guess. The first case will result in List.remove(int) being called, and the element at position 1 will be removed. The second case will result in List.remove(Integer) being called, and the element whose value is equal to Integer(1) will be removed. In both cases, the Java compiler selects the closest matching overload.
Yes, there is potential for confusion (and bugs) here, but it is a fairly uncommon use-case.
When the two List.remove methods were defined in Java 1.2, the overloads were not ambiguous. The problem only arose with the introduction of generics and autoboxing in Java 1.5. In hind-sight, it would have been better if one of the remove methods had been given a different name. But it is too late now.
Note that even if the VM did not do the right thing, which it does, you could still ensure proper behaviour by using the fact that remove(java.lang.Object) operates on arbitrary objects:
myList.remove(new Object() {
#Override
public boolean equals(Object other) {
int k = ((Integer) other).intValue();
return k == 1;
}
}
Simply I did like following as suggested by #decitrig in accepted answer first comment.
list.remove(Integer.valueOf(intereger_parameter));
This helped me. Thanks again #decitrig for your comment. It may help for some one.
Well here is the trick.
Let's take two examples here:
public class ArrayListExample {
public static void main(String[] args) {
Collection<Integer> collection = new ArrayList<>();
List<Integer> arrayList = new ArrayList<>();
collection.add(1);
collection.add(2);
collection.add(3);
collection.add(null);
collection.add(4);
collection.add(null);
System.out.println("Collection" + collection);
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(null);
arrayList.add(4);
arrayList.add(null);
System.out.println("ArrayList" + arrayList);
collection.remove(3);
arrayList.remove(3);
System.out.println("");
System.out.println("After Removal of '3' :");
System.out.println("Collection" + collection);
System.out.println("ArrayList" + arrayList);
collection.remove(null);
arrayList.remove(null);
System.out.println("");
System.out.println("After Removal of 'null': ");
System.out.println("Collection" + collection);
System.out.println("ArrayList" + arrayList);
}
}
Now let's have a look at the output:
Collection[1, 2, 3, null, 4, null]
ArrayList[1, 2, 3, null, 4, null]
After Removal of '3' :
Collection[1, 2, null, 4, null]
ArrayList[1, 2, 3, 4, null]
After Removal of 'null':
Collection[1, 2, 4, null]
ArrayList[1, 2, 3, 4]
Now let's analyze the output:
When 3 is removed from the collection it calls the remove() method of the collection which takes Object o as parameter. Hence it removes the object 3.
But in arrayList object it is overridden by index 3 and hence the 4th element is removed.
By the same logic of Object removal null is removed in both cases in the second output.
So to remove the number 3 which is an object we will explicitly need to pass 3 as an object.
And that can be done by casting or wrapping using the wrapper class Integer.
Eg:
Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);
I am trying to make a program in Java about the Tabulation method. For those unfamiliar, one of the steps in Tabulation method is to group binaries with the same number of 1's digits. So we put the group with the same number of 1's digit in a arraylist. So if we have five different groups (1st group containing no 1's digits, 2nd group containing one 1's digits, and so on), we store them in another arraylist. Thus an arraylist of an arraylist.
In the Tabulation method, we compare the elements from each group with the elements from the proceeding group. Each time we find a similar element from the next group (exactly one digit that differs), then we put them in a new list. This list is again grouped from the number of 1's digit. Thus, we have an arraylist of an arraylist of an arraylist.
What I have here is a part of my code:
allTables.add(new ArrayList<ArrayList<String>>().set(count, new ArrayList<String>().add(mintermBinaries[i])));
allTables is just an arraylist of an arraylist of an arraylist. The integer count determines the number of 1's digit a binary has and sets it in that index, and finally mintermBinaries[i], is the ith index of the array that contains all binaries in ascending order. The whole code is within a for loop.
The problem is it won't compile because according to Eclipse, the arguments are not applicable. I don't know why.
After thinking about this a lot, I'm not sure if a three dimensional array is even a good thing to do. Can anyone help? What is a better way to solve this?
new ArrayList<ArrayList<String>>().set(
count,
new ArrayList<String>().add(mintermBinaries[i]))
The second argument of set(), which is supposed to be an ArrayList<String> (since you're calling it on an ArrayList<ArrayList<String>>), is the expression
new ArrayList<String>().add(mintermBinaries[i])
The type of this expression is the type of the value returned by the method add(). And add() returns a boolean. And a boolean is not an ArrayList<String>.
Don't try to write all your code in a single line. Replace that with
List<ArrayList<String>> listOfLists = new ArrayList<ArrayList<String>>();
ArrayList<String> innerList = new ArrayList<String>();
innerList.add(mintermBinaries[i]);
listOfLists.set(count, innerList);
As returninig result of List#add() and List#set() are different from what you expect, to use such one-liners, you need additional helper methods:
// Appends an item to the end of the list.
// Instead of `boolean`, returns modified list itself
static <T> List<T> add(List<T> list, T item) {
list.add(item);
return list;
}
// Sets an item to arbitrary position in `List`, expanding if needed.
// Instead of replaced item, returns modified list itself
static <T> List<T> set(List<T> list, int index, T item) {
if (list.size() <= index) {
for (int i = list.size(); i <= index; i++)
list.add(null);
}
list.set(index, item);
return list;
}
then you can write your code in one line:
add(allTables, set(new ArrayList<List<String>>(), count, add(new ArrayList<String>(), mintermBinaries[i])));
Although this is not very elegant and may be even confusing in your particular case (I'd also prefer to call List.add() and .set() sequentially), such approach may happen more clean and efficient in some situations.
On creating an arrayList using the below mentioned code snippet:
List arrayList = new ArrayList(16);
The internal implementation of ArrayList creates an array elementData of size 16 and assigns nullat every location. On doing something like arrayList.add(2,"HelloWorld") gives an IndexOutOfBoundException as the index at which the element is being added (i.e 2) is greater than the size attribute of the arrayList .
As clear from the javaDocs, the size attribute of the arrayList is initialized to 0 when the arrayList is initialized and is incremented by 1 everytime a new element is added to the arrayList
Can someone please explain, why the ArrayList dataStructure was designed this way in the first place. Even tho' the internal dataStructure elementData was initialized with 16 null values at the creation of arrayList, still it does not allow to add value at indeces > size; (assuming index <16 in this case). What was the idea to implement the add(index,object)
funtionality to be governed by the size attribute of the arrayList?
The purpose of having an internal array with a size greater then List.size() is to avoid re-allocating the array unnecessarily. If the internal array always had the same size as the List, then every time a new element is added, the internal array would have to be re-allocated, causing a performance penalty.
In fact, the default constructor of ArrayList constructs a list with an initial capacity of 10.
public ArrayList() {
this(10);
}
But why we need such an allocation? As you understand, if you indicate the size of ArrayList in advance, you can provide efficient for the list. Otherwise, after the number of elements exceeds the initial capacity of ArrayList, a new reallocation operation is performed for each element.
The documentation says:
public void add(int index, E element)
Throws:
IndexOutOfBoundsException -
if the index is out of range
(index < 0 || index > size())
As you can see, it throws IndexOutOfBoundsException if (index > size()).
Since ArrayList's "public int size()" returns elements which are not equal to null, your size equals to 0 (not 16 as you said in your example). In other words, if null values were counted as well, the size of each ArrayList that was created with default constructor would be 10.
Consequently, "arrayList.add(2, "HelloWorld")" throws IndexOutOfBoundsException since index = 2 but size() = 0.
Edit:
I think when you mount your argument, you use this as base:
String[] arr = new String[5];
arr[3] = "hello";
System.out.println(arr[3]);
Then, you think why you can give a value in an array element directly but why you cannot do the same thing while using add(int index, E element) method of ArrayList. Actually, it is true but there is no condition to implement ArrayList as complete counterpart of Array. In other words, this method is conditioned with that rule since it is nature of ArrayList. As we all know, when you create an array, you specify its size in square brackets. The constructor of ArrayList which takes int as parameter does not do the same thing. It performs just an imaginary allocation. Yes, it could specify its initial size with this allocation or after add(int index, E element) is called, size could be increased by one. However, ArrayList is implemented to provide an array-like structure which has continuity with respect to index number but has no fixed size. Thence, there are some other higher level of abstraction examples do this task. To exemplify, LinkedHashMap structure.
You can not add object at a specific index till it contains null. You just need to add object using add method and then you can update values on a index.
For Example.
ArrayList<Integer> arrlist = new ArrayList<Integer>(5);
// use add() method to add elements in the list
arrlist.add(15);
arrlist.add(22);
arrlist.add(30);
arrlist.add(40);
// adding element 25 at third position
arrlist.add(2,25);
You rarely need to specify the capacity of an ArrayList, it can improve the performance only if you know how many elements your ArrayList will hold.
ArrayList is simply a List that can automatically be grown or shrink. Using List, you never need to add an element in the place n if the list is empty, you simply link it to the previous node (unless it's the head of course) - that's the idea of ArrayList except the fact that it can be grown/shrink automatically.
See the java doc of ArrayList's add(int index,
E element) method. Here you can find the ArrayIndexOutOfBound exception occurred when if the index is out of range (index < 0 || index > size()).
You declared an ArrayList with an initial capacity 16. It doesn't mean that each of the 16 indexed position of the ArrayList contains element. It just mention the initial capacity and when it necessary it will grow it's size dynamically.
See the source code the constructor from the ArrayList class -
/**
* Constructs an empty list with the specified initial capacity.
*
* #param initialCapacity the initial capacity of the list
* #exception IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
Here we can not find anything that told us - ArrayList will initiated with null value.
Update: Based on your comment I have done some experiment, since I'm not sure about whether an array of reference/non-primitive type will initialized with null. See the following code below. Run the the code by uncommenting each of line at per execution -
import java.util.List;
import java.util.ArrayList;
public class ArrayListTest{
public static void main(String[] args){
List<String> list1 = new ArrayList<String>(); //default with initial capacity 10
List<String> list2 = new ArrayList<String>(5);
List<String> list3 = new ArrayList<String>(5);
list2.add(null);
list2.add(null);
list2.add(null);
list3.add("zero");
list3.add("one");
list3.add("two");
//System.out.println(list1.get(4)); //IndexOutOfBoundException
//System.out.println(list2.get(0)); //null
//System.out.println(list2.get(2)); //null;
//System.out.println(list2.get(3)); //IndexOutOfBoundException
//System.out.println(list3.get(0)); //zero
//System.out.println(list3.get(2)); //two;
//System.out.println(list3.get(3)); //IndexOutOfBoundException
//list3.add(4, "four"); //IndexOutOfBoundException
}
}
Here you can see list2.get(0) and list2.get(2) gives you null. Because we put null at these index. But list2.get(3) doesn't give null since we didn't put null at index 3. So it seems array of reference/non-primitive type won't initialize with null. list2.get(3) gives IndexOutOfBoundException.
You found the same scenario for the list3. where I didn't put any null in this list. Even when we are trying to add some value at index 4 of list3 it gives IndexOutOfBoundException. Since the index 4 is not available for the list3. But you can add some value at index 2 of list2. Cause at index 2 of this list I have inserted null manually.
So in long story short (I think) - new ArrayList<SomeType>(givenSize) wouldn't initialize an array with givenSize with all element setting to null.
Hope it will Help.
Thanks.
If I run this operation on List<Integer> for example, it works as expected (removes first 5 elements), but when I run it on a list of my objects, nothing happens (list stays the same).
list.subList(0, 5).clear();
My class is a pojo that doesn't implement equals or hashCode, if that matters.
UPDATE:
The implementation I am using is ArrayList, which is returned from Hibernate query. There is nothing to show, really. Sublist doesn't return an empty list.
Here is an example for those who don't beleive it works on a list of Integers:
List<Integer> testList = new ArrayList<Integer>();
for(int i=0;i<10;i++) {
testList.add(i);
}
testList.subList(0, 5).clear();
for(int i=0;i<testList.size();i++) {
System.out.print(testList.get(i)+" ");
}
The result is 5 6 7 8 9
UPDATE2: Actually everything is working as expected, don't know how I couldn't see that (got confused by numbers of results). Sorry for false alarm :) This question could be deleted.
It works on my machinetm
import java.util.*;
import static java.lang.System.out;
class SubListExample {
public static void main( String [] args ) {
List<RandomObject> testList = new ArrayList<RandomObject>();
for(int i=0;i<10;i++) {
testList.add( new RandomObject() );
}
System.out.println( "Before: " + testList );
testList.subList(0, 5).clear();
System.out.println( "After: "+ testList );
}
}
class RandomObject {
static Random generator = new Random();
int id = generator.nextInt(100);
public String toString(){
return "ro("+id+")";
}
}
Produces:
$ java SubListExample
Before: [ro(68), ro(97), ro(48), ro(45), ro(43), ro(69), ro(45), ro(8), ro(88), ro(40)]
After: [ro(69), ro(45), ro(8), ro(88), ro(40)]
So, the problem is not in ArrayList nor in your objects.
I don't think Hibernate returns a plain old ArrayList ( may be it does )
Try printing
System.out.println( "That hibernate list.class.name = "
+ listReturnedByHibernate.getClass().getName() );
And let us know if it is in fact an ArrayList
edit - Looks like I was wrong, but leaving my original answer here anyway:
Are you sure that it works with a List<Integer>? It shouldn't.
The method subList() returns a separate List. If you remove elements from that list, it shouldn't affect the original list. The API docs for List.subList() say this:
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
Clearing a list is not a non-structural change; only changing the elements in the list are non-structural changes.
This has nothing to do with whether your POJO has equals or hashCode methods or not.
edit - I just tried it out with an ArrayList and it does work (not only with Integer, but also with my own object as a list element).
Two things I can think of are:
list.sublist(0, 5) returns an empty list, therefore .clear() does nothing.
Not sure of the inner workings of the List implementation you're using (ArrayList, LinkedList, etc), but having the equals and hashCode implemented may be important.
I had a simiarl issue with Maps, where HashMap definitely needs the hashCode implementation.
Have you tried creating a List of your objects manually and doing the same thing (without Hibernate)? It seems possible to me that this has to do with Hibernate's lazy loading of data... if you haven't read the data in the returned List, it may not have been loaded yet (since sublists themselves are just views). In that case, it's possible clear would do nothing.
Is it possible that the List returned from Hibernate is not modifiable? i.e. wrapped by Collections.unmodifiableList()