Arrays.asList() of an array - java

What is wrong with this conversion?
public int getTheNumber(int[] factors) {
ArrayList<Integer> f = new ArrayList(Arrays.asList(factors));
Collections.sort(f);
return f.get(0)*f.get(f.size()-1);
}
I made this after reading the solution found in Create ArrayList from array. The second line (sorting) in getTheNumber(...) causes the following exception:
Exception in thread "main" java.lang.ClassCastException: [I cannot be cast to java.lang.Comparable]
What is wrong here? I do realize that sorting could be done with Arrays.sort(), I'm just curious about this one.

Let's consider the following simplified example:
public class Example {
public static void main(String[] args) {
int[] factors = {1, 2, 3};
ArrayList<Integer> f = new ArrayList(Arrays.asList(factors));
System.out.println(f);
}
}
At the println line this prints something like "[[I#190d11]" which means that you have actually constructed an ArrayList that contains int arrays.
Your IDE and compiler should warn about unchecked assignments in that code. You should always use new ArrayList<Integer>() or new ArrayList<>() instead of new ArrayList(). If you had used it, there would have been a compile error because of trying to pass List<int[]> to the constructor.
There is no autoboxing from int[] to Integer[], and anyways autoboxing is only syntactic sugar in the compiler, so in this case you need to do the array copy manually:
public static int getTheNumber(int[] factors) {
List<Integer> f = new ArrayList<Integer>();
for (int factor : factors) {
f.add(factor); // after autoboxing the same as: f.add(Integer.valueOf(factor));
}
Collections.sort(f);
return f.get(0) * f.get(f.size() - 1);
}

You are trying to cast int[] to Integer[], this is not possible.
You can use commons-lang's ArrayUtils to convert the ints to Integers before getting the List from the array:
public int getTheNumber(int[] factors) {
Integer[] integers = ArrayUtils.toObject(factors);
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(integers));
Collections.sort(f);
return f.get(0)*f.get(f.size()-1);
}

there are two cause of this exception:
1
Arrays.asList(factors) returns a List<int[]> where factors is an int array
2
you forgot to add the type parameter to:
ArrayList<Integer> f = new ArrayList(Arrays.asList(factors));
with:
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(factors));
resulting in a compile-time error:
found : java.util.List<int[]>
required: java.util.List<java.lang.Integer>

Use java.utils.Arrays:
public int getTheNumber(int[] factors) {
int[] f = (int[])factors.clone();
Arrays.sort(f);
return f[0]*f[(f.length-1];
}
Or if you want to be efficient avoid all the object allocation just actually do the work:
public static int getTheNumber(int[] array) {
if (array.length == 0)
throw new IllegalArgumentException();
int min = array[0];
int max = array[0];
for (int i = 1; i< array.length;++i) {
int v = array[i];
if (v < min) {
min = v;
} else if (v > max) {
max = v;
}
}
return min * max;
}

I think you have found an example where auto-boxing doesn't really work. Because Arrays.asList(T... a) has a varargs parameter the compiler apparently considers the int[] and returns a List<int[]> with a single element in it.
You should change the method into this:
public int getTheNumber(Integer[] factors) {
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(factors));
Collections.sort(f);
return f.get(0) * f.get(f.size() - 1);
}
and possibly add this for compatibility
public int getTheNumber(int[] factors) {
Integer[] factorsInteger = new Integer[factors.length];
for(int ii=0; ii<factors.length; ++ii) {
factorsInteger[ii] = factors[ii];
}
return getTheNumber(factorsInteger);
}

Arrays.asList(factors) returns a List<int[]>, not a List<Integer>. Since you're doing new ArrayList instead of new ArrayList<Integer> you don't get a compile error for that, but create an ArrayList<Object> which contains an int[] and you then implicitly cast that arraylist to ArrayList<Integer>. Of course the first time you try to use one of those "Integers" you get an exception.

This works from Java 5 to 7:
public int getTheNumber(Integer... factors) {
ArrayList<Integer> f = new ArrayList<Integer>(Arrays.asList(factors));
Collections.sort(f);
return f.get(0)*f.get(f.size()-1);
}
In Java 4 there is no vararg... :-)

this is from Java API
"sort
public static void sort(List list)
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list)."
it has to do with implementing the Comparable interface

As far as I understand it, the sort function in the collection class can only be used to sort collections implementing the comparable interface.
You are supplying it a array of integers.
You should probably wrap this around one of the know Wrapper classes such as Integer.
Integer implements comparable.
Its been a long time since I have worked on some serious Java, however reading some matter on the sort function will help.

Related

Error : Type mismatch: cannot convert from List<Integer> to ArrayList<Integer>

package set01;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class DFTList {
static List<Integer>[] list;
static boolean[] visited;
public DFTList(int nodes) {
list = new ArrayList[nodes];
visited = new boolean[nodes];
for(int i=0;i<nodes;i++) {
list[i] = new ArrayList<>();
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter no. of nodes : ");
int nodes = scan.nextInt();
DFTList obj = new DFTList(nodes);
System.out.println("Enter no.of vertex : ");
int vertex = scan.nextInt();
for(int i=0;i<vertex;i++) {
int v1 = scan.nextInt();
int v2 = scan.nextInt();
list[v1].add(v2);
list[v2].add(v1);
}
solve(0);
}
public static void solve(int a) {
visited[a] = true;
ArrayList<Integer> l = list[a];
}
}
In the above code snippet, At the DFTList constructor, I have inserted ArrayList object at all the indices of the array. But when I try to retrieve the same object at the solve method and store it under the same reference, I encountered an error stating that "Type mismatch: cannot convert from List to ArrayList". Why does this error occur?
The list variable is a List<Integer>[], which means that any type of List (ArrayList, LinkedList, etc.) could be stored in it. When retrieving an element from this list, all the Java compiler knows is that it's some type of List; it doesn't know the specific type of List (even though you as the programmer know that you're only storing ArrayList items in the array). Therefore, ArrayList<Integer> l = list[a] is a compilation failure because the compiler can't guarantee that the element retrieved from the array is an ArrayList and not a different List type.
There are a few ways to address this issue. Assuming you wanted to keep list as an array, the most idiomatic approach would be to change its type to List<Integer>[] instead of ArrayList<Integer>[]. Since you are not using any methods or other API specific to ArrayList, the List interface is a better choice for this type.
public static void solve(int a) {
visited[a] = true;
List<Integer> l = list[a];
}
Another, less idiomatic approach would be to change the type of the list variable from List<Integer>[] to ArrayList<Integer>[]. This change would cause your variable assignment to work as already written.
public class DFTList {
static ArrayList<Integer>[] list;
...
}
The final approach you could use when you have an array of the interface type (List<Integer> in this case) would be to cast the element to the concrete type when storing it to the variable. This is basically telling the compiler that you as the developer know the element is of that subtype, so even though it cannot guarantee the assignment, it will allow it to happen. This approach defers the type checking — ensuring the List is the ArrayList subtype — until the code is actually run (at runtime). If the stored element is a subtype other than ArrayList when the code is run (e.g. if it's a LinkedList), then Java will throw a ClassCastException since the assignment to ArrayList cannot happen.
Casting like this is not ideal, as it removes guarantees by the compiler that all types being used are guaranteed to be valid at runtime. However, there are times where it is necessary and appropriate.
public static void solve(int a) {
visited[a] = true;
ArrayList<Integer> l = (ArrayList<Integer>) list[a];
}
list is declared as a List<Integer>[] (read: an array of Lists of Integers). The fact that the value in each element is actually an ArrayList is inconsequential - as far as the compiler is concerned, every element is a List.
You could either explicitly downcast the array access:
ArrayList<Integer> l = (ArrayList<Integer>)list[a];
Or, more idiomatically, if you aren't relying on any specific method ArrayList has that isn't present in the List interface, you could declare l as a List<Integer>:
List<Integer> l = list[a];
you are mixing C++ with Java!!
check the following reproducable code:
public class DFTList {
static List<Integer>[] list;
static boolean[] visited;
public DFTList(int nodes) {
list = new ArrayList[nodes];
visited = new boolean[nodes];
for(int i=0;i<nodes;i++) {
list[i] = new ArrayList<>();
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter no. of nodes : ");
int nodes = scan.nextInt();
DFTList obj = new DFTList(nodes);
System.out.println("Enter no.of vertex : ");
int vertex = scan.nextInt();
for(int i=0;i<vertex;i++) {
int v1 = scan.nextInt();
int v2 = scan.nextInt();
list[v1].add(v2);
list[v2].add(v1);
}
solve(0);
}
public static void solve(int a) {
visited[a] = true;
List<Integer> l = list[a];
}
}
Note 0
there is no pointer like concept in java therefore following snippet gives you compile time error:
* list[i] = new ArrayList<>();
Note 1
you are assigning List interface to l type therefore use below syntax.
List<Integer> l = list[a];

How to populate generic array to main

I've got a generic array class and I want to return an array in the main so I can use the sort method that I have ready in the main. I understand that the constructor has an array in it so I'm wondering if I can use that. Or do I need to set up a new method to return this.array ? Also it returns a generic array, how do I choose the type in main?
public class dynamicArray <T>{
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
Here I chose the integer type for the class. I'm not sure how can I extract the
array from the constructor.
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int [] arr = array.populate();
mergeSort(arr);
System.out.println(array.toString());
}
Unfortunately, arrays and generics don't work well together. Take a look at the source code of java's ArrayList - it is implemented with an Object[] and not a T[] - then every method will cast to T (which costs literally zero, it's just ugly and causes compiler warnings). I advise you do the same here: Arrays actually KNOW their component type (unlike a list of Ts, which does not, there is no method on a java.util.List that you can invoke to get the component type), and therefore casting Object[] to T[] is just wrong; java allows this solely for backwards compatibility reasons.
Basically, you can't work with T[] without things being subtly wrong and a lot of compiler errors.
In this specific case? I would strenuously advise you to use a private List<T> array; field instead of a T[] field.
Your call to array.populate() (that seems like a bizarre name for this method!) IS retrieving the array you created in the constructor. You are doing what you're asking for: "Extracting the array from the constructor" - invoking populate() on the object returned by the new dynamicArray<Integer>() is doing exactly that.
NB: You have a typo in your source code. it's new dynamicArray<Integer>();, not new<Integer>dynamicArray();. Perhaps that's causing some issues?
NB2: Java conventions dictate it's DynamicArray, and something like getBackingArray (instead of populate).
I think you ask two question :
How to set Integer type of that array object.
How to get Integer[] to int[]
Here is the code :
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
public void add(T x) {
array[++index] = x;
}
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int[] arr = Arrays.stream(array.populate())
.mapToInt(i -> i)
.toArray();
System.out.println(array.toString());
}
Answer for 1st question is you can not set Integer type because there wasn't any add method in your class. Answer for 2nd question is you try to convert Integer[] to int[] but there is no direct way to cast this. you just need to change Integer -> Object then Object -> int. This can be done easily using streams which is in Java 8 and i have used lambda here for showing power of lambda function.
Here is a possible alternative. Pass the type of array to the constructor. But essentially you are creating a limited form of ArrayList so you may just as well use that. Note that this still has the limitation that you can't use primitive arrays as the array type.
dynamicArray<Integer> array = new dynamicArray<>(new Integer[0]);
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
Integer[] a = array.getArray();
System.out.println(Arrays.toString(a));
}
class dynamicArray<T> {
private int size = 0;
private T[] array;
public dynamicArray(T[] a) {
array = a;
}
public void add(T value) {
if (array.length == size) {
array = Arrays.copyOf(array, size == 0 ? 10 : size*2);
}
array[size++] = value;
}
#SuppressWarnings("unchecked")
public T[] getArray() {
// need to copy the array since the length and size could be different.
T[] arrayCopy = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
System.arraycopy(array, 0, arrayCopy, 0, size);
return arrayCopy;
}
}

how can I pass List<int> into a varargs method [duplicate]

This question already has answers here:
How to convert an ArrayList containing Integers to primitive int array?
(19 answers)
Closed 4 years ago.
How can I convert a List<Integer> to int[] in Java?
I'm confused because List.toArray() actually returns an Object[], which can be cast to neither Integer[] nor int[].
Right now I'm using a loop to do so:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
for(int i = 0; i < ret.length; i++)
ret[i] = list.get(i);
return ret;
}
Is there's a better way to do this?
This is similar to the question
How can I convert int[] to Integer[] in Java?.
With streams added in Java 8 we can write code like:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Thought process:
The simple Stream#toArray returns an Object[] array, so it is not what we want. Also, Stream#toArray(IntFunction<A[]> generator) doesn't do what we want, because the generic type A can't represent the primitive type int
So it would be nice to have some stream which could handle the primitive type int instead of the wrapper Integer, because its toArray method will most likely also return an int[] array (returning something else like Object[] or even boxed Integer[] would be unnatural here). And fortunately Java 8 has such a stream which is IntStream
So now the only thing we need to figure out is how to convert our Stream<Integer> (which will be returned from list.stream()) to that shiny IntStream.
Quick searching in documentation of Stream while looking for methods which return IntStream points us to our solution which is mapToInt(ToIntFunction<? super T> mapper) method. All we need to do is provide a mapping from Integer to int.
Since ToIntFunction is functional interface we can provide its instance via lambda or method reference.
Anyway to convert Integer to int we can use Integer#intValue so inside mapToInt we can write:
mapToInt( (Integer i) -> i.intValue() )
(or some may prefer: mapToInt(Integer::intValue).)
But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type int (the lambda used in mapToInt is an implementation of the ToIntFunction interface which expects as body a method of type: int applyAsInt(T value) which is expected to return an int).
So we can simply write:
mapToInt((Integer i)->i)
Also, since the Integer type in (Integer i) can be inferred by the compiler because List<Integer>#stream() returns a Stream<Integer>, we can also skip it which leaves us with
mapToInt(i -> i)
Unfortunately, I don't believe there really is a better way of doing this due to the nature of Java's handling of primitive types, boxing, arrays and generics. In particular:
List<T>.toArray won't work because there's no conversion from Integer to int
You can't use int as a type argument for generics, so it would have to be an int-specific method (or one which used reflection to do nasty trickery).
I believe there are libraries which have autogenerated versions of this kind of method for all the primitive types (i.e. there's a template which is copied for each type). It's ugly, but that's the way it is I'm afraid :(
Even though the Arrays class came out before generics arrived in Java, it would still have to include all the horrible overloads if it were introduced today (assuming you want to use primitive arrays).
In addition to Commons Lang, you can do this with Guava's method Ints.toArray(Collection<Integer> collection):
List<Integer> list = ...
int[] ints = Ints.toArray(list);
This saves you having to do the intermediate array conversion that the Commons Lang equivalent requires yourself.
The easiest way to do this is to make use of Apache Commons Lang. It has a handy ArrayUtils class that can do what you want. Use the toPrimitive method with the overload for an array of Integers.
List<Integer> myList;
... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));
This way you don't reinvent the wheel. Commons Lang has a great many useful things that Java left out. Above, I chose to create an Integer list of the right size. You can also use a 0-length static Integer array and let Java allocate an array of the right size:
static final Integer[] NO_INTS = new Integer[0];
....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));
Java 8 has given us an easy way to do this via streams...
Using the collections stream() function and then mapping to ints, you'll get an IntStream. With the IntStream we can call toArray() which gives us int []
int [] ints = list.stream().mapToInt(Integer::intValue).toArray();
to int []
to IntStream
Use:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list)
ret[i++] = e;
return ret;
}
This slight change to your code is to avoid expensive list indexing (since a List is not necessarily an ArrayList, but it could be a linked list, for which random access is expensive).
Here is a Java 8 single line code for this:
public int[] toIntArray(List<Integer> intList){
return intList.stream().mapToInt(Integer::intValue).toArray();
}
If you are simply mapping an Integer to an int then you should consider using parallelism, since your mapping logic does not rely on any variables outside its scope.
int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();
Just be aware of this
Note that parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores. While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism.
There are two ways to map Integers to their primitive form:
Via a ToIntFunction.
mapToInt(Integer::intValue)
Via explicit unboxing with lambda expression.
mapToInt(i -> i.intValue())
Via implicit (auto-) unboxing with lambda expression.
mapToInt(i -> i)
Given a list with a null value
List<Integer> list = Arrays.asList(1, 2, null, 4, 5);
Here are three options to handle null:
Filter out the null values before mapping.
int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
Map the null values to a default value.
int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
Handle null inside the lambda expression.
int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
This simple loop is always correct! no bugs
int[] integers = new int[myList.size()];
for (int i = 0; i < integers.length; i++) {
integers[i] = myList.get(i);
}
I've noticed several uses of for loops, but you don't even need anything inside the loop. I mention this only because the original question was trying to find less verbose code.
int[] toArray(List<Integer> list) {
int[] ret = new int[ list.size() ];
int i = 0;
for( Iterator<Integer> it = list.iterator();
it.hasNext();
ret[i++] = it.next() );
return ret;
}
If Java allowed multiple declarations in a for loop the way C++ does, we could go a step further and do for(int i = 0, Iterator it...
In the end though (this part is just my opinion), if you are going to have a helping function or method to do something for you, just set it up and forget about it. It can be a one-liner or ten; if you'll never look at it again you won't know the difference.
There is really no way of "one-lining" what you are trying to do, because toArray returns an Object[] and you cannot cast from Object[] to int[] or Integer[] to int[].
int[] ret = new int[list.size()];
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {
ret[i] = iter.next();
}
return ret;
Also try Dollar (check this revision):
import static com.humaorie.dollar.Dollar.*
...
List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();
With Eclipse Collections, you can do the following if you have a list of type java.util.List<Integer>:
List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
If you already have an Eclipse Collections type like MutableList, you can do the following:
MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
Note: I am a committer for Eclipse Collections
I would recommend you to use the List<?> skeletal implementation from the Java collections API. It appears to be quite helpful in this particular case:
package mypackage;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
// Helper method to convert int arrays into Lists
static List<Integer> intArrayAsList(final int[] a) {
if(a == null)
throw new NullPointerException();
return new AbstractList<Integer>() {
#Override
public Integer get(int i) {
return a[i]; // Autoboxing
}
#Override
public Integer set(int i, Integer val) {
final int old = a[i];
a[i] = val; // Auto-unboxing
return old; // Autoboxing
}
#Override
public int size() {
return a.length;
}
};
}
public static void main(final String[] args) {
int[] a = {1, 2, 3, 4, 5};
Collections.reverse(intArrayAsList(a));
System.out.println(Arrays.toString(a));
}
}
Beware of boxing/unboxing drawbacks.
Using a lambda you could do this (compiles in JDK lambda):
public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[ i++ ] = element;
}
return ints;
};
List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };
int[] results = transformService.transform(inputs);
}
public interface TransformService {
int[] transform(List<Integer> inputs);
}

Unchecked warnings for Arraylist

Why am I getting these 4 warnings from -Xlint and what should I do about them? I'm just starting in Java, so am likely missing something obvious.
import java.util.*;
class CompareGerbils implements Comparator {
public int compare(Object o1, Object o2) {
return ((Gerbil)o2).number() - ((Gerbil)o1).number();
}
}
class Gerbil {
int gerbilNumber;
Gerbil(int gN) {
gerbilNumber = gN;
}
int number() {
return gerbilNumber;
}
}
public class lt {
public static void main(String[] args) {
// I'd like to be able to add both ints and strings to list
ArrayList list = new ArrayList();
//unchecked call warning:
list.add(1);
//unchecked call warning:
list.add("b");
ArrayList<Gerbil> gerbillist = new ArrayList<Gerbil>();
for(int i = 0; i < 5; i++) {
gerbillist.add(new Gerbil(i));
}
//unchecked conversion warning
//unchecked method invocation
Collections.sort(gerbillist, new CompareGerbils());
}
}
EDIT: replies so far have answered the Arraylist declaration. How about the sort warnings at the bottom of the code? thanks
You're getting this because you have not defined a data type for the ArrayList list. The only way to add both Strings and Integers in list without getting warnings is by defining it as ArrayList<Object> list - which is what happens here implicitly (line list.add(1); is implicitly converting 1 to new Integer(1) - this is called autoboxing). Also note that if you want to have both Strings and Integers in lists, the sorting method does not really make sense - how are you expecting things to get sorted, alphabetically or numerically?
Edit: Also, it is not considered good practice to declare a concrete type (i.e. ArrayList<Object> list) unless you have very good reasons to do so. It is recommended that you initialise using an interface, i.e. List<Object> list.
So, your code would have to be like this (note the part Comparator<Gerbil> which fixes the warning in Collections.sort):
// I'd like to be able to add both ints and strings to list
List<Object> list = new ArrayList<Object>();
list.add(new Integer(1));
list.add(new String("b"));
List<Gerbil> gerbillist = new ArrayList<Gerbil>();
for(int i = 0; i < 5; i++) {
gerbillist.add(new Gerbil(i));
}
Collections.sort(gerbillist, new Comparator<Gerbil>() {
public int compare(Gerbil o1, Gerbil o2) {
int diff = o1.getNumber() - o2.getNumber();
if (diff > 0)
return 1;
else if (diff <0)
return -1;
else
return 0;
}
});
With respect to the Gerbil class, I suggest you use the form getNumber as a method name rather than number - it's a de facto standard for method names to retrieve the value of a member variable (and, respectively setNumber(int value) for setting it):
class Gerbil {
int gerbilNumber;
Gerbil(int gN) {
gerbilNumber = gN;
}
int getNumber() {
return gerbilNumber;
}
}
The warning occurs when you are using a non-generic type in a context where a generic is expected. The compile is saying, you might be right, but I cannot check the type for you.
You cna either;
Make the type the correct generic.
Turn off the warning with #SuppressWarnings
Ignore the warning.
EDIT: In this example, you have to pick a super class/interface of the elements in the list.
// I'd like to be able to add both ints and strings to list
List<Object> list = new ArrayList<Object>();
list.add(1);
list.add("b");
Instead of Object you could pick Seralizable or Comparable however eneither is likely to be useful. Indeed a List<Object> is rarely useful except in exercises.
The correct way to implement the Comparator is to use comparison. Using - is only valid if you know this cannot possibly overflow. e.g. 2000000000 - -2000000000 < 0 whereas you might expect 2000000000 - -2000000000 > 0
class CompareGerbils implements Comparator<Gerbil> {
public int compare(Gerbil a, Gerbil b) {
return a.number() > b.number() ? +1
: a.number() < b.number() ? -1 : 0;
}
}
For testing purposes I suggest trying to sort a List which is not already sorted. A simple way to do this is to use the shuffle() method. This could still be sorted but the large the list, the less likely that is the case.
Collections.shuffle(gerbillis);
public static void main(String[] args) {
final List<Object> list = new ArrayList<Object>();
list.add(1);
list.add("b");
final List<Gerbil> gerbillist = new ArrayList<Gerbil>();
for (int i = 0; i < 5; i++) {
gerbillist.add(new Gerbil(i));
}
Collections.sort(gerbillist, new CompareGerbils());
}
you need to know Generics http://download.oracle.com/javase/1.5.0/docs/guide/language/generics.html
you are trying to add primitive and a string in arraylist.
either u do this to take anything
List<Object> list = new ArrayList<Object>();
or if you want to allow only strings
List<String> list = new ArrayList<String>();

How can I convert List<Integer> to int[] in Java? [duplicate]

This question already has answers here:
How to convert an ArrayList containing Integers to primitive int array?
(19 answers)
Closed 4 years ago.
How can I convert a List<Integer> to int[] in Java?
I'm confused because List.toArray() actually returns an Object[], which can be cast to neither Integer[] nor int[].
Right now I'm using a loop to do so:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
for(int i = 0; i < ret.length; i++)
ret[i] = list.get(i);
return ret;
}
Is there's a better way to do this?
This is similar to the question
How can I convert int[] to Integer[] in Java?.
With streams added in Java 8 we can write code like:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Thought process:
The simple Stream#toArray returns an Object[] array, so it is not what we want. Also, Stream#toArray(IntFunction<A[]> generator) doesn't do what we want, because the generic type A can't represent the primitive type int
So it would be nice to have some stream which could handle the primitive type int instead of the wrapper Integer, because its toArray method will most likely also return an int[] array (returning something else like Object[] or even boxed Integer[] would be unnatural here). And fortunately Java 8 has such a stream which is IntStream
So now the only thing we need to figure out is how to convert our Stream<Integer> (which will be returned from list.stream()) to that shiny IntStream.
Quick searching in documentation of Stream while looking for methods which return IntStream points us to our solution which is mapToInt(ToIntFunction<? super T> mapper) method. All we need to do is provide a mapping from Integer to int.
Since ToIntFunction is functional interface we can provide its instance via lambda or method reference.
Anyway to convert Integer to int we can use Integer#intValue so inside mapToInt we can write:
mapToInt( (Integer i) -> i.intValue() )
(or some may prefer: mapToInt(Integer::intValue).)
But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type int (the lambda used in mapToInt is an implementation of the ToIntFunction interface which expects as body a method of type: int applyAsInt(T value) which is expected to return an int).
So we can simply write:
mapToInt((Integer i)->i)
Also, since the Integer type in (Integer i) can be inferred by the compiler because List<Integer>#stream() returns a Stream<Integer>, we can also skip it which leaves us with
mapToInt(i -> i)
Unfortunately, I don't believe there really is a better way of doing this due to the nature of Java's handling of primitive types, boxing, arrays and generics. In particular:
List<T>.toArray won't work because there's no conversion from Integer to int
You can't use int as a type argument for generics, so it would have to be an int-specific method (or one which used reflection to do nasty trickery).
I believe there are libraries which have autogenerated versions of this kind of method for all the primitive types (i.e. there's a template which is copied for each type). It's ugly, but that's the way it is I'm afraid :(
Even though the Arrays class came out before generics arrived in Java, it would still have to include all the horrible overloads if it were introduced today (assuming you want to use primitive arrays).
In addition to Commons Lang, you can do this with Guava's method Ints.toArray(Collection<Integer> collection):
List<Integer> list = ...
int[] ints = Ints.toArray(list);
This saves you having to do the intermediate array conversion that the Commons Lang equivalent requires yourself.
The easiest way to do this is to make use of Apache Commons Lang. It has a handy ArrayUtils class that can do what you want. Use the toPrimitive method with the overload for an array of Integers.
List<Integer> myList;
... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));
This way you don't reinvent the wheel. Commons Lang has a great many useful things that Java left out. Above, I chose to create an Integer list of the right size. You can also use a 0-length static Integer array and let Java allocate an array of the right size:
static final Integer[] NO_INTS = new Integer[0];
....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));
Java 8 has given us an easy way to do this via streams...
Using the collections stream() function and then mapping to ints, you'll get an IntStream. With the IntStream we can call toArray() which gives us int []
int [] ints = list.stream().mapToInt(Integer::intValue).toArray();
to int []
to IntStream
Use:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list)
ret[i++] = e;
return ret;
}
This slight change to your code is to avoid expensive list indexing (since a List is not necessarily an ArrayList, but it could be a linked list, for which random access is expensive).
Here is a Java 8 single line code for this:
public int[] toIntArray(List<Integer> intList){
return intList.stream().mapToInt(Integer::intValue).toArray();
}
If you are simply mapping an Integer to an int then you should consider using parallelism, since your mapping logic does not rely on any variables outside its scope.
int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();
Just be aware of this
Note that parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores. While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism.
There are two ways to map Integers to their primitive form:
Via a ToIntFunction.
mapToInt(Integer::intValue)
Via explicit unboxing with lambda expression.
mapToInt(i -> i.intValue())
Via implicit (auto-) unboxing with lambda expression.
mapToInt(i -> i)
Given a list with a null value
List<Integer> list = Arrays.asList(1, 2, null, 4, 5);
Here are three options to handle null:
Filter out the null values before mapping.
int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
Map the null values to a default value.
int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
Handle null inside the lambda expression.
int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
This simple loop is always correct! no bugs
int[] integers = new int[myList.size()];
for (int i = 0; i < integers.length; i++) {
integers[i] = myList.get(i);
}
I've noticed several uses of for loops, but you don't even need anything inside the loop. I mention this only because the original question was trying to find less verbose code.
int[] toArray(List<Integer> list) {
int[] ret = new int[ list.size() ];
int i = 0;
for( Iterator<Integer> it = list.iterator();
it.hasNext();
ret[i++] = it.next() );
return ret;
}
If Java allowed multiple declarations in a for loop the way C++ does, we could go a step further and do for(int i = 0, Iterator it...
In the end though (this part is just my opinion), if you are going to have a helping function or method to do something for you, just set it up and forget about it. It can be a one-liner or ten; if you'll never look at it again you won't know the difference.
There is really no way of "one-lining" what you are trying to do, because toArray returns an Object[] and you cannot cast from Object[] to int[] or Integer[] to int[].
int[] ret = new int[list.size()];
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {
ret[i] = iter.next();
}
return ret;
Also try Dollar (check this revision):
import static com.humaorie.dollar.Dollar.*
...
List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();
With Eclipse Collections, you can do the following if you have a list of type java.util.List<Integer>:
List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
If you already have an Eclipse Collections type like MutableList, you can do the following:
MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
Note: I am a committer for Eclipse Collections
I would recommend you to use the List<?> skeletal implementation from the Java collections API. It appears to be quite helpful in this particular case:
package mypackage;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
// Helper method to convert int arrays into Lists
static List<Integer> intArrayAsList(final int[] a) {
if(a == null)
throw new NullPointerException();
return new AbstractList<Integer>() {
#Override
public Integer get(int i) {
return a[i]; // Autoboxing
}
#Override
public Integer set(int i, Integer val) {
final int old = a[i];
a[i] = val; // Auto-unboxing
return old; // Autoboxing
}
#Override
public int size() {
return a.length;
}
};
}
public static void main(final String[] args) {
int[] a = {1, 2, 3, 4, 5};
Collections.reverse(intArrayAsList(a));
System.out.println(Arrays.toString(a));
}
}
Beware of boxing/unboxing drawbacks.
Using a lambda you could do this (compiles in JDK lambda):
public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[ i++ ] = element;
}
return ints;
};
List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };
int[] results = transformService.transform(inputs);
}
public interface TransformService {
int[] transform(List<Integer> inputs);
}

Categories

Resources