Sorting Map keys when keys are arrays - java

I have a HashMap<Float[], Integer> and I'll probably need to convert it to TreeMap. How will keys (i.e. arrays) of TreeMap be sorted? By their first elements?
I was going to run a simple test but it resulted in error somehow:
public class treeMapTest {
public static void main(String[] args) {
Integer arr1[] = {9, 0, 3};
Integer arr2[] = {2, 2, 2};
Integer arr3[] = {4, 2, 1};
TreeMap<Integer[], Integer> tm = new TreeMap<Integer[], Integer>();
tm.put(arr1, 7);
tm.put(arr2, 7);
tm.put(arr3, 7);
System.out.println(tm);
}
}
Thank you.

Arrays don't have natural ordering (i.e. they don't implement the Comparable interface), which is why your code throws an exception when you instantiate the TreeMap using the parameterless constructor.
You must supply a Comparator<Integer[]> to the TreeMap constructor in order to define the ordering yourself.
BTW, using arrays as keys in a HashMap is a bad idea (since arrays don't override the default implementation of equals() and hashCode()), so it's a good thing you are switching to a TreeMap.

This might be syntactically correct but it's not practically useful.
The map uses equals() method to determine whether 2 keys are equal.
Arrays inherit equals() and hashcode() methods from Object class. Therefore when you want to search for a particular key(array object), you won't find it unless reference of the initial array object is passed.
For e.g.
Integer arr1[] = {9, 0, 3};
and
Integer arr1_copy[] = {9, 0, 3};
are 2 different objects and default equals() will fail.
If however, you need to use arrays as key, what you can do instead is create a class with an array as it's member and override hashcode() and equals() methods for this class and use this class as key.

Arrays does not have a natural ordering. One way to solve it and make it predictable would be to do something like this:
TreeMap<Integer[], Integer> tm = new TreeMap<>((a1, a2) -> Integer.compare(a1[0], a2[0]) );
This will compare the first element of each array. If the arrays can be empty you will need to alter it a little bit so it doesn't throw an exception.

The keys areidentified by hashcode. That means the hashcode of the Array object representing the arrays, not the actual content of the array.
Which is most likely not what you had in mind, even if it may work for the scenario you're dealing with.
If you think that by moving elements around in the arrays you're going to change the sorting of the items in the value buckets of the hash map you're however sorely mistaken.

You should provide Comparator in Treemap for you sorting preference.
public static void main(String[] args) {
Integer arr1[] = {9, 0, 3};
Integer arr2[] = {2, 2, 2};
Integer arr3[] = {4, 2, 1};
TreeMap<Integer[], Integer> tm = new TreeMap<Integer[], Integer>(new Comparator<Integer[]>() {
#Override
public int compare(Integer[] o1, Integer[] o2) {
int cmp=o1[0].compareTo(o2[0]);
return cmp;
}
});
tm.put(arr1, 7);
tm.put(arr2, 7);
tm.put(arr3, 7);
for(Integer[] o1:tm.keySet())
System.out.println(o1[0]);
}

Related

Problem when working with arrays in Java - code does not go inside the "if" statement [duplicate]

How do I convert an array to a list in Java?
I used the Arrays.asList() but the behavior (and signature) somehow changed from Java SE 1.4.2 (docs now in archive) to 8 and most snippets I found on the web use the 1.4.2 behaviour.
For example:
int[] numbers = new int[] { 1, 2, 3 };
Arrays.asList(numbers)
on 1.4.2 returns a list containing the elements 1, 2, 3
on 1.5.0+ returns a list containing the array 'numbers'
In many cases it should be easy to detect, but sometimes it can slip unnoticed:
Assert.assertTrue(Arrays.asList(numbers).indexOf(4) == -1);
In your example, it is because you can't have a List of a primitive type. In other words, List<int> is not possible.
You can, however, have a List<Integer> using the Integer class that wraps the int primitive. Convert your array to a List with the Arrays.asList utility method.
Integer[] numbers = new Integer[] { 1, 2, 3 };
List<Integer> list = Arrays.asList(numbers);
See this code run live at IdeOne.com.
In Java 8, you can use streams:
int[] numbers = new int[] { 1, 2, 3 };
Arrays.stream(numbers)
.boxed()
.collect(Collectors.toList());
We cannot have List<int> as int is a primitive type so we can only have List<Integer>.
Java 16
Java 16 introduces a new method on Stream API called toList(). This handy method returns an unmodifiable List containing the stream elements. So, trying to add a new element to the list will simply lead to UnsupportedOperationException.
int[] ints = new int[] {1,2,3,4,5};
Arrays.stream(ints).boxed().toList();
Java 8 (int array)
int[] ints = new int[] {1,2,3,4,5};
List<Integer> list11 =Arrays.stream(ints).boxed().collect(Collectors.toList());
Java 8 and below (Integer array)
Integer[] integers = new Integer[] {1,2,3,4,5};
List<Integer> list21 = Arrays.asList(integers); // returns a fixed-size list backed by the specified array.
List<Integer> list22 = new ArrayList<>(Arrays.asList(integers)); // good
List<Integer> list23 = Arrays.stream(integers).collect(Collectors.toList()); //Java 8 only
Need ArrayList and not List?
In case we want a specific implementation of List e.g. ArrayList then we can use toCollection as:
ArrayList<Integer> list24 = Arrays.stream(integers)
.collect(Collectors.toCollection(ArrayList::new));
Why list21 cannot be structurally modified?
When we use Arrays.asList the size of the returned list is fixed because the list returned is not java.util.ArrayList, but a private static class defined inside java.util.Arrays. So if we add or remove elements from the returned list, an UnsupportedOperationException will be thrown. So we should go with list22 when we want to modify the list. If we have Java8 then we can also go with list23.
To be clear list21 can be modified in sense that we can call list21.set(index,element) but this list may not be structurally modified i.e. cannot add or remove elements from the list. You can also check this answer of mine for more explanation.
If we want an immutable list then we can wrap it as:
List<Integer> list22 = Collections.unmodifiableList(Arrays.asList(integers));
Another point to note is that the method Collections.unmodifiableList returns an unmodifiable view of the specified list. An unmodifiable view collection is a collection that is unmodifiable and is also a view onto a backing collection. Note that changes to the backing collection might still be possible, and if they occur, they are visible through the unmodifiable view.
We can have a truly immutable list in Java 9 and 10.
Truly Immutable list
Java 9:
String[] objects = {"Apple", "Ball", "Cat"};
List<String> objectList = List.of(objects);
Java 10 (Truly Immutable list):
We can use List.of introduced in Java 9. Also other ways:
List.copyOf(Arrays.asList(integers))
Arrays.stream(integers).collect(Collectors.toUnmodifiableList());
Speaking about conversion way, it depends on why do you need your List.
If you need it just to read data. OK, here you go:
Integer[] values = { 1, 3, 7 };
List<Integer> list = Arrays.asList(values);
But then if you do something like this:
list.add(1);
you get java.lang.UnsupportedOperationException.
So for some cases you even need this:
Integer[] values = { 1, 3, 7 };
List<Integer> list = new ArrayList<Integer>(Arrays.asList(values));
First approach actually does not convert array but 'represents' it like a List. But array is under the hood with all its properties like fixed number of elements. Please note you need to specify type when constructing ArrayList.
The problem is that varargs got introduced in Java 5 and unfortunately, Arrays.asList() got overloaded with a vararg version too. So Arrays.asList(numbers) is understood by the Java 5 compiler as a vararg parameter of int arrays.
This problem is explained in more details in Effective Java 2nd Ed., Chapter 7, Item 42.
I recently had to convert an array to a List. Later on the program filtered the list attempting to remove the data. When you use the Arrays.asList(array) function, you create a fixed size collection: you can neither add nor delete. This entry explains the problem better than I can: Why do I get an UnsupportedOperationException when trying to remove an element from a List?.
In the end, I had to do a "manual" conversion:
List<ListItem> items = new ArrayList<ListItem>();
for (ListItem item: itemsArray) {
items.add(item);
}
I suppose I could have added conversion from an array to a list using an List.addAll(items) operation.
Even shorter:
List<Integer> list = Arrays.asList(1, 2, 3, 4);
Using Arrays
This is the simplest way to convert an array to List. However, if you try to add a new element or remove an existing element from the list, an UnsupportedOperationException will be thrown.
Integer[] existingArray = {1, 2, 3};
List<Integer> list1 = Arrays.asList(existingArray);
List<Integer> list2 = Arrays.asList(1, 2, 3);
// WARNING:
list2.add(1); // Unsupported operation!
list2.remove(1); // Unsupported operation!
Using ArrayList or Other List Implementations
You can use a for loop to add all the elements of the array into a List implementation, e.g. ArrayList:
List<Integer> list = new ArrayList<>();
for (int i : new int[]{1, 2, 3}) {
list.add(i);
}
Using Stream API in Java 8
You can turn the array into a stream, then collect the stream using different collectors: The default collector in Java 8 use ArrayList behind the screen, but you can also impose your preferred implementation.
List<Integer> list1, list2, list3;
list1 = Stream.of(1, 2, 3).collect(Collectors.toList());
list2 = Stream.of(1, 2, 3).collect(Collectors.toCollection(ArrayList::new));
list3 = Stream.of(1, 2, 3).collect(Collectors.toCollection(LinkedList::new));
See also:
Why do we use autoboxing and unboxing in Java?
When to use LinkedList over ArrayList?
Another workaround if you use Apache commons-lang:
int[] numbers = new int[] { 1, 2, 3 };
Arrays.asList(ArrayUtils.toObject(numbers));
Where ArrayUtils.toObject converts int[] to Integer[]
In Java 9 you have the even more elegant solution of using immutable lists via the new convenience factory method List.of:
List<String> immutableList = List.of("one","two","three");
(shamelessly copied from here )
One-liner:
List<Integer> list = Arrays.asList(new Integer[] {1, 2, 3, 4});
If you are targeting Java 8 (or later), you can try this:
int[] numbers = new int[] {1, 2, 3, 4};
List<Integer> integers = Arrays.stream(numbers)
.boxed().collect(Collectors.<Integer>toList());
NOTE:
Pay attention to the Collectors.<Integer>toList(), this generic method helps you to avoid the error "Type mismatch: cannot convert from List<Object> to List<Integer>".
you have to cast in to array
Arrays.asList((Object[]) array)
Using Guava:
Integer[] array = { 1, 2, 3};
List<Integer> list = Lists.newArrayList(sourceArray);
Using Apache Commons Collections:
Integer[] array = { 1, 2, 3};
List<Integer> list = new ArrayList<>(6);
CollectionUtils.addAll(list, array);
I've had the same problem and wrote a generic function that takes an array and returns an ArrayList of the same type with the same contents:
public static <T> ArrayList<T> ArrayToArrayList(T[] array) {
ArrayList<T> list = new ArrayList<T>();
for(T elmt : array) list.add(elmt);
return list;
}
Given Array:
int[] givenArray = {2,2,3,3,4,5};
Converting integer array to Integer List
One way: boxed() -> returns the IntStream
List<Integer> givenIntArray1 = Arrays.stream(givenArray)
.boxed()
.collect(Collectors.toList());
Second Way: map each element of the stream to Integer and then collect
NOTE:
Using mapToObj you can covert each int element into string stream, char stream etc by casing i to (char)i
List<Integer> givenIntArray2 = Arrays.stream(givenArray)
.mapToObj(i->i)
.collect(Collectors.toList());
Converting One array Type to Another Type Example:
List<Character> givenIntArray2 = Arrays.stream(givenArray)
.mapToObj(i->(char)i)
.collect(Collectors.toList());
So it depends on which Java version you are trying-
Java 7
Arrays.asList(1, 2, 3);
OR
final String arr[] = new String[] { "G", "E", "E", "K" };
final List<String> initialList = new ArrayList<String>() {{
add("C");
add("O");
add("D");
add("I");
add("N");
}};
// Elements of the array are appended at the end
Collections.addAll(initialList, arr);
OR
Integer[] arr = new Integer[] { 1, 2, 3 };
Arrays.asList(arr);
In Java 8
int[] num = new int[] {1, 2, 3};
List<Integer> list = Arrays.stream(num)
.boxed().collect(Collectors.<Integer>toList())
Reference - http://www.codingeek.com/java/how-to-convert-array-to-list-in-java/
Can you improve this answer please as this is what I use but im not 100% clear. It works fine but intelliJ added new WeatherStation[0]. Why the 0 ?
public WeatherStation[] removeElementAtIndex(WeatherStation[] array, int index)
{
List<WeatherStation> list = new ArrayList<WeatherStation>(Arrays.asList(array));
list.remove(index);
return list.toArray(new WeatherStation[0]);
}
Use this to convert an Array arr to List.
Arrays.stream(arr).collect(Collectors.toList());
An example of defining a generic method to convert an array to a list:
public <T> List<T> fromArrayToList(T[] a) {
return Arrays.stream(a).collect(Collectors.toList());
}
use two line of code to convert array to list if you use it in integer value
you must use autoboxing type for primitive data type
Integer [] arr={1,2};
List<Integer> listInt=Arrays.asList(arr);
As of Java 8, the following should do
int[] temp = {1, 2, 3, 4, 5};
List<Integer> tempList = Arrays.stream(temp).boxed().collect(Collectors.toList());
If you are trying to optimize for memory, etc., (and don't want to pull in external libraries) it's simpler than you think to implement your own immutable "array view list" – you just need to extend java.util.AbstractList.
class IntArrayViewList extends AbstractList<Integer> {
int[] backingArray;
int size;
IntArrayViewList(int[] backingArray, int size) {
this.backingArray = backingArray;
this.size = size;
}
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int i = 0;
#Override
public boolean hasNext() {
return i < size;
}
#Override
public Integer next() {
return get(i++);
}
};
}
public int size() {
return size;
}
public Integer get(int i) {
return backingArray[i];
}
}
int is a primitive. Primitives can’t accept null and have default value. Hence, to accept null you need to use wrapper class Integer.
Option 1:
int[] nos = { 1, 2, 3, 4, 5 };
Integer[] nosWrapped = Arrays.stream(nos).boxed()   
.toArray(Integer[]::new);
nosWrapped[5] = null // can store null
Option 2:
You can use any data structure that uses the wrapper class Integer
int[] nos = { 1, 2, 3, 4, 5 };
List<Integer> = Arrays.asList(nos)
I started looking at this by trying to reduce the amount of code preparing the input of some test cases. I see a lot of effort around trying to include advanced and new features along with Arrays.asList(), but below the code chosen due simplicity:
//Integer input[]
List<Integer> numbers = Arrays.asList(new Integer[]{1, 2 ,3, 4, 5, 4, 3, 2, 1, 3, 4});
//String input[]
List<String> names = Arrays.asList(new String[]{"Jhon", "Lucas", "Daniel", "Jim", "Sam"});
//String input[]
List<Character> letters = Arrays.asList(new Character[]{'A', 'B', 'K', 'J', 'F'});
Please notice that Anonymous array example will work just with Arrays of Non Primitive Types as the API uses Generics, that's the reason you can see several 2 line examples around, more info here: Why don't Java Generics support primitive types?
For newer JDKs there is another simpler option, the below examples are equivalent to the ones show above:
//Integer
List<Integer> numbers = Arrays.asList(1, 2 ,3, 4, 5, 4, 3, 2, 1, 3, 4);
//String
List<String> names = Arrays.asList("Jhon", "Lucas", "Daniel", "Jim", "Sam");
//Character
List<Character> letters = Arrays.asList('A', 'B', 'K', 'J', 'F');

Using collection to remove duplicate Lists

I have 3 Lists, two of which are duplicates. I want to store these Lists into one unit, removing all the duplicates, so I was thinking to add each List to a collection. This is what I tried:
List<Integer> coins1 = Arrays.asList(5, 5, 10);
List<Integer> coins2 = Arrays.asList(5, 10, 5);
List<Integer> coins3 = Arrays.asList(10, 10);
coins1.sort((a, b) -> a.compareTo(b));
coins2.sort((a, b) -> a.compareTo(b));
coins3.sort((a, b) -> a.compareTo(b));
Collection<List<Integer>> allCoinPossibilities = new TreeSet();
allCoinPossibilities.add(coins1);
allCoinPossibilities.add(coins2);
allCoinPossibilities.add(coins3);
I get an error "java.util.Arrays$ArrayList cannot be cast to java.lang.Comparable". The error makes sense, the Collection doesn't know how to compare each list to disallow duplicates. Do I need to override a compare method? If so, How would I do that? Is this the correct approach to solving this problem?
Thanks!
Make a HashSet and add everything into that.
At the end you'll be left with just the unique elements
List<Integer> coins1 = Arrays.asList(5, 5, 10);
List<Integer> coins2 = Arrays.asList(5, 10, 5);
List<Integer> coins3 = Arrays.asList(10, 10);
Set<Integer> dedupedCollection = new HashSet<Integer>();
dedupedCollection.add(coins1);
dedupedCollection.add(coins2);
dedupedCollection.add(coins3);
return dedupedCollection;
then you can return dedupedCollection; as the final set with no duplicartes.
Why not use a HashSet instead?
Lists already have a good hashCode implementation and a correct equals method.
Also, comparing Lists is not really logically possible - think about comparing two sets of numbers. How do I compare [2, 3, 8] with [1, 7, -2]?
Set<List<Integer>> noDuplicates = new HashSet<>();
noDuplicates.add(coins1);
noDuplicates.add(coins2);
noDuplicates.add(coins3);
//Now there are no duplicate lists.
Keep in mind that the lists must also have the same orderings, otherwise equals returns false. If you do not want this requirement you can also use a Set for your coins.
You can write your own comparator and pass that as an argument while creating the TreeSet, e.g.:
class ListComparator implements Comparator<List<Integer>>{
#Override
public int compare(List<Integer> o1, List<Integer> o2) {
// TODO comparison logic
return 0;
}
}
Collection<List<Integer>> allCoinPossibilities = new TreeSet(new ListComparator());

What's the fastest way to sort a HashMap alphanumerically (on a key that's an array of ints)?

HashMap<ArrayList<Integer>, String>
Iterating though this structure, I get:
[1 1 0], "gh"
[0 4 2], "gh"
[0 5 2], "qh"
However, I want to sort this on the key (in increasing order), to get
[0 4 2], "gh"
[0 5 2], "qh"
[1 1 0], "gh"
The first component is sorted first, then the second, then the third.
HashMaps have no inherent ordering.
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
Use a different data structure, or externally sort the keys yourself, before iterating. Either way, you'll need to write a Comparator<List<Integer>> since List<E> does not extend Comparable<List<E>>
List<List<Integer>> keys = new ArrayList<>(map.keySet());
Collections.sort(keys, new Comparator<List<Integer>>() {
#Override public int compare(List<Integer> a, List<Integer> b) {
// TODO handle edge cases, like lists of differing size
for (int i=0; i<Math.min(a.size(), b.size()); i++) {
int result = Integer.compare(a.get(i), b.get(i));
if (result != 0) {
return result;
}
}
return 0;
}
});
for (List<Integer> key : keys) {
String value = map.get(key);
// do something interesting with the value
}
N.B. it is generally a Bad Idea to use mutable keys in a map of any type. Personally, I've never had a need to – at least use an immutable list of integers instead.
TreeMap may be useful for you. There are a few ways to handle this. I would personally not use an ArrayList as the index to a Map. Instead, I'd fabricate a key from the ArrayList and include the actual ArrayList in the value.
In the case above, the value of the Map would be of this type:
class SomeClass() {
ArrayList<Integer> aList;
String aString; // gh and qh in your example.
public Integer getKey() {
// Do something here to create a suitable key from aList and return it.
}
}
(Structurally, this sort of class is probably more of what you want anyway - you don't want the List and the String separated if they are related, which they clearly seem to be.)
Now you'd make a TreeMap not a HashMap and add SomeClass instances:
TreeMap treeMap = new TreeMap();
SomeClass someClass = new SomeClass(...); // construct it somehow
treeMap.add(someClass.getKey(), someClass);
And Bob's your uncle.

Java addAll(collection) vs new ArrayList(collection)

Why do i get different behaviors with:
Collection col2 = new ArrayList(col);
Collection col2 = new ArrayList();
col2.addAll(col)
I'm working with viewers, and the code is complex, and i'm trying to explain the "root" of the problem. Another interesting fact is the next one...
//IF i use this code i have the correct behavior in my app:
public void updateCollection(Collection<Object> col) {
this.objectCollection.clear();
this.objectCollection.addAll(col);
}
//IF i use this code i have unexpected behavior in my app:
public void updateCollection(Collection<Object> col) {
this.objectCollection=new ArrayList(col);
}
This code works:
public void updateCollection(Collection<Object> col) {
this.objectCollection.clear();
this.objectCollection.addAll(col);
}
But this introduces problems:
public void updateCollection(Collection<Object> col) {
this.objectCollection = new ArrayList(col);
}
I suspect that this variation on your first method would introduce identical problems:
public void updateCollection(Collection<Object> col) {
this.objectCollection = new ArrayList();
this.objectCollection.clear();
this.objectCollection.addAll(col);
}
Why? Evidently you have another reference to objectCollection in use somewhere. Somewhere in your code, another object is saying (for instance):
myCopyOfObjectCollection = theOtherObject.objectCollection;
If you're using a getter, that doesn't change the underlying behavior - you are still keeping another reference around.
So if on initial assignment, say, the collection contained {1, 2, 3}, you start out with:
this.objectCollection: {1, 2, 3}
that.copyOfObjectCollection: {1, 2, 3}
When you assign a new ArrayList to this.objectCollection, and populate it with, say, {4, 5, 6}, you get this:
this.objectCollection: {4, 5, 6}
that.copyOfObjectCollection: {1, 2, 3}
So that is still pointing to the original ArrayList.
Collection col2 = new ArrayList(col);
will create a new ArrayList with size col.size() (+10%) and copy all elements from col into that array.
Collection col2 = new ArrayList();
will create a new ArrayList with initial size of 10 (at least in Sun implementation).
col2.addAll(col);
will copy all elements from col into the end of the col2 ArrayList, enlarging the backing array size, if needed.
So, depending on your col collection size, the behavior will be a bit different, but not too much.
It is preferable to use the first option - that will avoid at least one extra backing array expansion operation.
public List getAdminImIdsWithValidShortNames(){
return adminImIdsWithValidShortNames;
}
public void setAdminImIdsWithValidShortNames(List adminImIdsWithValidShortNames){
this.adminImIdsWithValidShortNames=adminImIdsWithValidShortNames;
}
I think, easy is beautiful, just generator setter/getter method is a good habit.
if you first clear, then addAll, the list need to clear all elements of list, then addAll will be extra backing array expansion operation, that's not science.
just replacement, this variable will be point to new List, the old list will be auto-GC.

Converting array to list in Java

How do I convert an array to a list in Java?
I used the Arrays.asList() but the behavior (and signature) somehow changed from Java SE 1.4.2 (docs now in archive) to 8 and most snippets I found on the web use the 1.4.2 behaviour.
For example:
int[] numbers = new int[] { 1, 2, 3 };
Arrays.asList(numbers)
on 1.4.2 returns a list containing the elements 1, 2, 3
on 1.5.0+ returns a list containing the array 'numbers'
In many cases it should be easy to detect, but sometimes it can slip unnoticed:
Assert.assertTrue(Arrays.asList(numbers).indexOf(4) == -1);
In your example, it is because you can't have a List of a primitive type. In other words, List<int> is not possible.
You can, however, have a List<Integer> using the Integer class that wraps the int primitive. Convert your array to a List with the Arrays.asList utility method.
Integer[] numbers = new Integer[] { 1, 2, 3 };
List<Integer> list = Arrays.asList(numbers);
See this code run live at IdeOne.com.
In Java 8, you can use streams:
int[] numbers = new int[] { 1, 2, 3 };
Arrays.stream(numbers)
.boxed()
.collect(Collectors.toList());
We cannot have List<int> as int is a primitive type so we can only have List<Integer>.
Java 16
Java 16 introduces a new method on Stream API called toList(). This handy method returns an unmodifiable List containing the stream elements. So, trying to add a new element to the list will simply lead to UnsupportedOperationException.
int[] ints = new int[] {1,2,3,4,5};
Arrays.stream(ints).boxed().toList();
Java 8 (int array)
int[] ints = new int[] {1,2,3,4,5};
List<Integer> list11 =Arrays.stream(ints).boxed().collect(Collectors.toList());
Java 8 and below (Integer array)
Integer[] integers = new Integer[] {1,2,3,4,5};
List<Integer> list21 = Arrays.asList(integers); // returns a fixed-size list backed by the specified array.
List<Integer> list22 = new ArrayList<>(Arrays.asList(integers)); // good
List<Integer> list23 = Arrays.stream(integers).collect(Collectors.toList()); //Java 8 only
Need ArrayList and not List?
In case we want a specific implementation of List e.g. ArrayList then we can use toCollection as:
ArrayList<Integer> list24 = Arrays.stream(integers)
.collect(Collectors.toCollection(ArrayList::new));
Why list21 cannot be structurally modified?
When we use Arrays.asList the size of the returned list is fixed because the list returned is not java.util.ArrayList, but a private static class defined inside java.util.Arrays. So if we add or remove elements from the returned list, an UnsupportedOperationException will be thrown. So we should go with list22 when we want to modify the list. If we have Java8 then we can also go with list23.
To be clear list21 can be modified in sense that we can call list21.set(index,element) but this list may not be structurally modified i.e. cannot add or remove elements from the list. You can also check this answer of mine for more explanation.
If we want an immutable list then we can wrap it as:
List<Integer> list22 = Collections.unmodifiableList(Arrays.asList(integers));
Another point to note is that the method Collections.unmodifiableList returns an unmodifiable view of the specified list. An unmodifiable view collection is a collection that is unmodifiable and is also a view onto a backing collection. Note that changes to the backing collection might still be possible, and if they occur, they are visible through the unmodifiable view.
We can have a truly immutable list in Java 9 and 10.
Truly Immutable list
Java 9:
String[] objects = {"Apple", "Ball", "Cat"};
List<String> objectList = List.of(objects);
Java 10 (Truly Immutable list):
We can use List.of introduced in Java 9. Also other ways:
List.copyOf(Arrays.asList(integers))
Arrays.stream(integers).collect(Collectors.toUnmodifiableList());
Speaking about conversion way, it depends on why do you need your List.
If you need it just to read data. OK, here you go:
Integer[] values = { 1, 3, 7 };
List<Integer> list = Arrays.asList(values);
But then if you do something like this:
list.add(1);
you get java.lang.UnsupportedOperationException.
So for some cases you even need this:
Integer[] values = { 1, 3, 7 };
List<Integer> list = new ArrayList<Integer>(Arrays.asList(values));
First approach actually does not convert array but 'represents' it like a List. But array is under the hood with all its properties like fixed number of elements. Please note you need to specify type when constructing ArrayList.
The problem is that varargs got introduced in Java 5 and unfortunately, Arrays.asList() got overloaded with a vararg version too. So Arrays.asList(numbers) is understood by the Java 5 compiler as a vararg parameter of int arrays.
This problem is explained in more details in Effective Java 2nd Ed., Chapter 7, Item 42.
I recently had to convert an array to a List. Later on the program filtered the list attempting to remove the data. When you use the Arrays.asList(array) function, you create a fixed size collection: you can neither add nor delete. This entry explains the problem better than I can: Why do I get an UnsupportedOperationException when trying to remove an element from a List?.
In the end, I had to do a "manual" conversion:
List<ListItem> items = new ArrayList<ListItem>();
for (ListItem item: itemsArray) {
items.add(item);
}
I suppose I could have added conversion from an array to a list using an List.addAll(items) operation.
Even shorter:
List<Integer> list = Arrays.asList(1, 2, 3, 4);
Using Arrays
This is the simplest way to convert an array to List. However, if you try to add a new element or remove an existing element from the list, an UnsupportedOperationException will be thrown.
Integer[] existingArray = {1, 2, 3};
List<Integer> list1 = Arrays.asList(existingArray);
List<Integer> list2 = Arrays.asList(1, 2, 3);
// WARNING:
list2.add(1); // Unsupported operation!
list2.remove(1); // Unsupported operation!
Using ArrayList or Other List Implementations
You can use a for loop to add all the elements of the array into a List implementation, e.g. ArrayList:
List<Integer> list = new ArrayList<>();
for (int i : new int[]{1, 2, 3}) {
list.add(i);
}
Using Stream API in Java 8
You can turn the array into a stream, then collect the stream using different collectors: The default collector in Java 8 use ArrayList behind the screen, but you can also impose your preferred implementation.
List<Integer> list1, list2, list3;
list1 = Stream.of(1, 2, 3).collect(Collectors.toList());
list2 = Stream.of(1, 2, 3).collect(Collectors.toCollection(ArrayList::new));
list3 = Stream.of(1, 2, 3).collect(Collectors.toCollection(LinkedList::new));
See also:
Why do we use autoboxing and unboxing in Java?
When to use LinkedList over ArrayList?
Another workaround if you use Apache commons-lang:
int[] numbers = new int[] { 1, 2, 3 };
Arrays.asList(ArrayUtils.toObject(numbers));
Where ArrayUtils.toObject converts int[] to Integer[]
In Java 9 you have the even more elegant solution of using immutable lists via the new convenience factory method List.of:
List<String> immutableList = List.of("one","two","three");
(shamelessly copied from here )
One-liner:
List<Integer> list = Arrays.asList(new Integer[] {1, 2, 3, 4});
If you are targeting Java 8 (or later), you can try this:
int[] numbers = new int[] {1, 2, 3, 4};
List<Integer> integers = Arrays.stream(numbers)
.boxed().collect(Collectors.<Integer>toList());
NOTE:
Pay attention to the Collectors.<Integer>toList(), this generic method helps you to avoid the error "Type mismatch: cannot convert from List<Object> to List<Integer>".
you have to cast in to array
Arrays.asList((Object[]) array)
Using Guava:
Integer[] array = { 1, 2, 3};
List<Integer> list = Lists.newArrayList(sourceArray);
Using Apache Commons Collections:
Integer[] array = { 1, 2, 3};
List<Integer> list = new ArrayList<>(6);
CollectionUtils.addAll(list, array);
I've had the same problem and wrote a generic function that takes an array and returns an ArrayList of the same type with the same contents:
public static <T> ArrayList<T> ArrayToArrayList(T[] array) {
ArrayList<T> list = new ArrayList<T>();
for(T elmt : array) list.add(elmt);
return list;
}
Given Array:
int[] givenArray = {2,2,3,3,4,5};
Converting integer array to Integer List
One way: boxed() -> returns the IntStream
List<Integer> givenIntArray1 = Arrays.stream(givenArray)
.boxed()
.collect(Collectors.toList());
Second Way: map each element of the stream to Integer and then collect
NOTE:
Using mapToObj you can covert each int element into string stream, char stream etc by casing i to (char)i
List<Integer> givenIntArray2 = Arrays.stream(givenArray)
.mapToObj(i->i)
.collect(Collectors.toList());
Converting One array Type to Another Type Example:
List<Character> givenIntArray2 = Arrays.stream(givenArray)
.mapToObj(i->(char)i)
.collect(Collectors.toList());
So it depends on which Java version you are trying-
Java 7
Arrays.asList(1, 2, 3);
OR
final String arr[] = new String[] { "G", "E", "E", "K" };
final List<String> initialList = new ArrayList<String>() {{
add("C");
add("O");
add("D");
add("I");
add("N");
}};
// Elements of the array are appended at the end
Collections.addAll(initialList, arr);
OR
Integer[] arr = new Integer[] { 1, 2, 3 };
Arrays.asList(arr);
In Java 8
int[] num = new int[] {1, 2, 3};
List<Integer> list = Arrays.stream(num)
.boxed().collect(Collectors.<Integer>toList())
Reference - http://www.codingeek.com/java/how-to-convert-array-to-list-in-java/
Can you improve this answer please as this is what I use but im not 100% clear. It works fine but intelliJ added new WeatherStation[0]. Why the 0 ?
public WeatherStation[] removeElementAtIndex(WeatherStation[] array, int index)
{
List<WeatherStation> list = new ArrayList<WeatherStation>(Arrays.asList(array));
list.remove(index);
return list.toArray(new WeatherStation[0]);
}
Use this to convert an Array arr to List.
Arrays.stream(arr).collect(Collectors.toList());
An example of defining a generic method to convert an array to a list:
public <T> List<T> fromArrayToList(T[] a) {
return Arrays.stream(a).collect(Collectors.toList());
}
use two line of code to convert array to list if you use it in integer value
you must use autoboxing type for primitive data type
Integer [] arr={1,2};
List<Integer> listInt=Arrays.asList(arr);
As of Java 8, the following should do
int[] temp = {1, 2, 3, 4, 5};
List<Integer> tempList = Arrays.stream(temp).boxed().collect(Collectors.toList());
If you are trying to optimize for memory, etc., (and don't want to pull in external libraries) it's simpler than you think to implement your own immutable "array view list" – you just need to extend java.util.AbstractList.
class IntArrayViewList extends AbstractList<Integer> {
int[] backingArray;
int size;
IntArrayViewList(int[] backingArray, int size) {
this.backingArray = backingArray;
this.size = size;
}
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int i = 0;
#Override
public boolean hasNext() {
return i < size;
}
#Override
public Integer next() {
return get(i++);
}
};
}
public int size() {
return size;
}
public Integer get(int i) {
return backingArray[i];
}
}
int is a primitive. Primitives can’t accept null and have default value. Hence, to accept null you need to use wrapper class Integer.
Option 1:
int[] nos = { 1, 2, 3, 4, 5 };
Integer[] nosWrapped = Arrays.stream(nos).boxed()   
.toArray(Integer[]::new);
nosWrapped[5] = null // can store null
Option 2:
You can use any data structure that uses the wrapper class Integer
int[] nos = { 1, 2, 3, 4, 5 };
List<Integer> = Arrays.asList(nos)
I started looking at this by trying to reduce the amount of code preparing the input of some test cases. I see a lot of effort around trying to include advanced and new features along with Arrays.asList(), but below the code chosen due simplicity:
//Integer input[]
List<Integer> numbers = Arrays.asList(new Integer[]{1, 2 ,3, 4, 5, 4, 3, 2, 1, 3, 4});
//String input[]
List<String> names = Arrays.asList(new String[]{"Jhon", "Lucas", "Daniel", "Jim", "Sam"});
//String input[]
List<Character> letters = Arrays.asList(new Character[]{'A', 'B', 'K', 'J', 'F'});
Please notice that Anonymous array example will work just with Arrays of Non Primitive Types as the API uses Generics, that's the reason you can see several 2 line examples around, more info here: Why don't Java Generics support primitive types?
For newer JDKs there is another simpler option, the below examples are equivalent to the ones show above:
//Integer
List<Integer> numbers = Arrays.asList(1, 2 ,3, 4, 5, 4, 3, 2, 1, 3, 4);
//String
List<String> names = Arrays.asList("Jhon", "Lucas", "Daniel", "Jim", "Sam");
//Character
List<Character> letters = Arrays.asList('A', 'B', 'K', 'J', 'F');

Categories

Resources