Assignment statement not working - java

List<Integer> list = Collections.shuffle(list);
This assignment doesn't work. It gives "incompatible types" even though it's clearly a List and .shuffle() takes a List. So why won't this thing work?

Check the javadoc. Collections.shuffle has a void return type. Create your List first, then shuffle. For example:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Collections.shuffle(list);
System.out.println("Shuffled List: " + list);

There are actually two issues:
You cannot access a variable before you initialize/declare it, even the code List list = new ArrayList(list); will not work, because the right operand of the assignment is parsed before the left operand.
As mentioned by #Reimeus Collections.shuffle() has a void return type, thus you cannot assign it (the "result") to a variable. The method shuffle() changes the same list given as input (might be not intuitive for functional programmers).

Related

Remove multi object from arraylist JAVA [duplicate]

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);

Seeming Discrepancy in Arrays.copyOf

Why this question is not a possible duplication of How Arrays.asList(int[]) can return List<int[]>?.
That question doesn't really answer my particular situation as I am trying to figure out if there is a discrepancy in my use of Arrays.copyOf.
CASE 1: Supposed deep copy of the array
// Creating a integer array, populating its values
int[] src = new int[2];
src[0] = 2;
src[1] = 3;
// Create a copy of the array
int [] dst= Arrays.copyOf(src,src.length);
Assert.assertArrayEquals(src, dst);
// Now change one element in the original
dst[0] = 4;
// Following line throws an exception, (which is expected) if the copy is a deep one
Assert.assertArrayEquals(src, dst);
CASE 2:
Here is where things seem to be weird:
What I am trying to do with the below method (lifted verbatim from a book) is to create an immutable list view of a copy of the input array arguments. That way, if the input array changes, the contents of the returned list don't change.
#SafeVarargs
public static <T> List<T> list(T... t) {
return Collections.unmodifiableList(new ArrayList<>(Arrays.asList(Arrays.copyOf(t, t.length))));
}
int[] arr2 = new int[2];
arr2[0] = 2;
arr2[1] = 3;
// Create an unmodifiable list
List<int[]> list2 = list(arr2);
list2.stream().forEach(s -> System.out.println(Arrays.toString(s)));
// Prints [2, 3] as expected
arr2[0] = 3;
list2.stream().forEach(s -> System.out.println(Arrays.toString(s)));
// Prints [3, 3] which doesn't make sense to me... I would have thought it would print [2, 3] and not be affected by my changing the value of the element.
The contradiction that I see is that in one case (Case 1), Arrays.copyOf seems to be a deep copy, whereas in the other case (Case 2), it seems like a shallow one. The changes to the original array seem to have written through to the list, even though I have copied the array in creating my unmodifiable list.
Would someone be able to help me resolve this discrepancy?
First of all, your list method performs an unnecessary step, you don't need the copyOf operation, so here goes:
#SafeVarargs
public static <T> List<T> list(T... t) {
return Collections.unmodifiableList(
new ArrayList<>(Arrays.asList(t))
);
}
The ArrayList constructor already copies the incoming list, so you're safe there.
Next, when you are calling your list() method with an int[], that array is considered to be a single element of type int[], because the type erasure of your T... is Object..., and int is primitive. There is no way you can make your method do a deep copy inside the list without either changing the parameter types or doing an instanceOf check and performing the copy manually inside the method. I'd say the wisest thing to do is probably to move the Arrays.copyOf() call outside the method:
List<int[]> list2 = list(Arrays.copyOf(arr2));

How Java compiler knows which function to use remove(int index) or remove(Object o)? [duplicate]

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);

java : Understanding Arrays.asList(T...array) method for primitive types

I wrote following code and was surprised to see the output:
Integer a = 211;
int b = 211;
int[] array = {210,211,212};
System.out.println(Arrays.asList(array).contains(a));
System.out.println(Arrays.asList(array).contains(b));
Output:
false
false
I found this question and some other questions linked to it and learned that asList method doesn't Autobox stuffs. I checked the returned type in eclipse javadoc preview:
I couldn't quite understand this return type. int[] is an object and not a primitive so its fine. I'm sure that I'm not getting List<Integer> (something which I expected) but I'm not sure how to use the thing which is being returned. My questions are:
1. How exactly do I expect that list methods will work when I'm expecting an List of Integer and getting a List of int[] ?
2. In case of Strings the return type is List of String and not List of String[]. What sort of implementation differences are there?
3. What good is this method for primitives if things are so uncertain?
There are obviously 3 questions here so lets tackle them one by one:
How exactly do I expect that list methods will work when I'm expecting an List of Integer and getting a List of int[] ?
Well, List methods will work exactly as expected, a List<T> is a list of types T. Here T is an int[] so a List<int[]> will contains arrays as each element:
[{1, 2}, {3, 4}, {1, 6}]
So get(i) will return the ith element. In the case of Arrays.asList the List contains a single element, namely the int[] so:
int[] array = {210,211,212};
List<int[]> list = Arrays.asList(array);
Will be
[{210, 211, 212}]
And so
list.get(0)[0] == 210
In case of Strings the return type is List of String and not List of String[]. What sort of implementation differences are there?
String is an Object, not a primitive type. The difference follows from that.
What good is this method for primitives if things are so uncertain?
Things are not uncertain. This method results in defined and predictable behaviour. It's just not very useful for primitives. This is (yet another) side effect of combining Java's type system with generics.
Note with Java 8 the conversion of an int[] to a List<Integer> is very simple:
List<Integer> list = Arrays.stream(array).
boxed().
collect(toList());
You are not getting a Lit or a List (which can't be), you're getting a List of arrays of integer.
So your list does not contain 211, it contains an array that then contains 211.
The array is not "unrolled" into the list, it is added "as is" to a newly created list.
So :
System.out.println(Arrays.asList(array).contains(array)); // Will return true
System.out.println(Arrays.asList(a).contains(a)); // Will return true
It is because Arrays.asList() is a variadic generic function. Change this,
int[] array = {210,211,212};
to
Integer[] array = { 210, 211, 212 };
And the output will be true and true.
Arrays.asList takes objects as params. Since int[] is an object, you get the List.
If you want a list of integers you should do Arrays.asList(211,212,213).
int[] array = {210,211,212};
Arrays.asList(array)
is equal to
List<int[]> asList = Arrays.asList(array);
Change
int[] array = {210,211,212}; to Integer[] array = {210,211,212}; and it will work.
and its equals to List<Integer> asList = Arrays.asList(array);

How to convert an int[] array to a List?

I expected this code to display true:
int[] array = {1, 2};
System.out.println(Arrays.asList(array).contains(1));
The method Arrays.asList(T ...) is, when generics are erased and varargs are transformed, actually equal to a method of type Arrays.ofList(Object[]) (which is the, binary equivalent, JDK 1.4 version of the same Method).
An array of primitives is an Object (see also this question), but not an Object[], so the compiler thinks you are using the varargs version and generates an Object array around your int array. You could illustrate what's happening by adding an extra step:
int[] array = {1, 2};
List<int[]> listOfArrays = Arrays.asList(array);
System.out.println(listOfArrays.contains(1));
This compiles and is equivalent to your code. It also obviously returns false.
The compiler translates varargs calls into calls with a single array, so calling a varargs method that expects parameters T ... with parameters T t1, T t2, T t3 is equivalent to calling it with new T[]{t1, t2, t3} but the special case here is that varargs with primitives will be autoboxed before the array is created if the method needs an object array. So the compiler thinks the int array is passed in as a single Object and creates a single element array of type Object[], which it passes to asList().
So here's the above code once again, the way the compiler implements it internally:
int[] array = {1, 2};
// no generics because of type erasure
List listOfArrays = Arrays.asList(new Object[]{array});
System.out.println(listOfArrays.contains(1));
Here are some good and bad ways to call Arrays.asList() with int values:
// These versions use autoboxing (which is potentially evil),
// but they are simple and readable
// ints are boxed to Integers, then wrapped in an Object[]
List<Integer> good1 = Arrays.asList(1,2,3);
// here we create an Integer[] array, and fill it with boxed ints
List<Integer> good2 = Arrays.asList(new Integer[]{1,2,3});
// These versions don't use autoboxing,
// but they are very verbose and not at all readable:
// this is awful, don't use Integer constructors
List<Integer> ugly1 = Arrays.asList(
new Integer(1),new Integer(2),new Integer(3)
);
// this is slightly better (it uses the cached pool of Integers),
// but it's still much too verbose
List<Integer> ugly2 = Arrays.asList(
Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)
);
// And these versions produce compile errors:
// compile error, type is List<int[]>
List<Integer> bad1 = Arrays.asList(new int[]{1,2,3});
// compile error, type is List<Object>
List<Integer> bad2 = Arrays.asList(new Object[]{1,2,3});
Reference:
Java Tutorial > Classes and Objects > Passing Information to a Method or a Constructor > Varargs
Arrays.asList(T ...)
But to actually solve your problem in a simple way:
There are some library solutions in Apache Commons / Lang (see Bozho's answer) and in Google Guava:
Ints.contains(int[], int) checks whether an array of ints contains a given int
Ints.asList(int ...) creates a List of Integers from an int array
The Arrays.asList(array) will result in a singleton list of an int[].
It works as you expect if you change int[] to Integer[]. Don't know if that helps you though.
Arrays.asList(ArrayUtils.toObjectArray(array))
(ArrayUtils is from commons-lang)
But if you want to just call contains there is no need of that. Simply use Arrays.binarySearch(..) (sort the array first)
This
System.out.println(Arrays.asList(array).contains(array));
returns true.
It seems like your understanding of Arrays.asList(T... a) is wrong. You wouldn't be the first person to make an assumption as to how it works.
Try it with
System.out.println(Arrays.asList(1, 2).contains(1));
Autoboxing just doesn't work the way you want it to in this case. The following code may be a bit verbose, but does the job of converting an int array to a list:
List<Integer> list = new ArrayList<Integer>(array.length);
for (int value : array) {
list.add(value);
}
The following code displays true:
Integer[] array = {1, 2};
System.out.println(Arrays.asList(array).contains(1));
(Your version fails, since Int's not beeing objects, but Int[] is an object. Therefor you will call asList(T... a) with one element beeing a Collection, since it is not possible to have an Collection a.)
When you call
Arrays.asList(array)
on your array of primitives, you get a List instance containing one object: an array of int values! You have to first convert the array of primitives into an array of objects, as #Bozho suggests in his answer.
If you only want to check whether the array contains certain element just iterate over array and search for element. This will take o(n/2). All other solutions are less effective. Any method that copies array to list must iterate over array and therefore this operation only requires n atomic assignments.
I dont think there is a method call you could use. Try it like this
List<Integer> list = new ArrayList<Integer>();
for (int index = 0; index < array.length; index++)
{
list.add(array[index]);
}

Categories

Resources