So there's Arrays.asList(T... a) but this works on varargs.
What if I already have the array in a T[] a? Is there a convenience method to create a List<T> out of this, or do I have to do it manually as:
static public <T> List<T> arrayAsList(T[] a)
{
List<T> result = new ArrayList<T>(a.length);
for (T t : a)
result.add(t);
return result;
}
Just because it works with varargs doesn't mean you can't call it normally:
String[] x = { "a", "b", "c" };
List<String> list = Arrays.asList(x);
The only tricky bit is if T is Object, where you should use a cast to tell the compiler whether it should wrap the argument in an array or not:
Object[] x = ...;
List<Object> list = Arrays.asList((Object[]) x);
or
Object[] x = ...;
List<Object[]> list = Arrays.asList((Object) x);
As you probably already know, there is a Static class called java.util.Collections which has a number of useful methods for dealing wit arrays such as searching and sorting.
As for your question, the Collection interface specifies methods to add, remove and toArray, amongst others. For one reason or another, the API's authors decided that the add and addAll method will be the only input functions provided to the user.
One explanation for why Java Lists cannot add arrays of objects is that Lists use an iterator and iterators are more strict in their scrolling (i.e. going to the next value) than Arrays which do not have to have all their index values i=(1, 2, 5, 9, 22, ...).
Also, Arrays are not type safe; that is, they cannot guarantee that all their elements conform to a specific super-class or interface, whereas generics (of which List is a member) can guarantee type safety. Hence, the list has the chance to validate each item using the add method.
I think that you can rest assure that your method of adding an array to a list is one of the most (if not most) efficient way of achieving this effect in Java.
Related
There are two existing methods named getDetails(...). One expects a minimum of one mandatory parameter and the other expects a collection (doesn't validate the content/size of the collection).
The problem is that the collection is sometimes passed as empty and according to my business case, I always expect a minimum of one value, to be passed. So, I need to make that method private, which accepts Collections.
// There are two params, to make sure that at-least one is passed by the caller
public static CustomerContext getDetails(int id, int... ids) {
Collection<Integer> idCollection = Instream.of(ids).boxed().collect(Collectors.toSet());
if(!idCollection.contains(id)){
idCollection.add(id);
}
return getDetails(idCollection);
}
I'm planning to make the below method scope to private so that the callers would not call this method with Zero attributes.
public static CustomerContext getDetails(Collection<Integer> idCollection) {
return getDetails(idCollection,false);
}
One of the caller methods is passing Collection object to getDetails like below,
CustomerContext.getDetails(id.getDetails().values());
The id.getDetails() is as below,
public Map<Id,Integer> getDetails(){
return Collections.unmodifiableMap(details);
}
I'm looking for a way to convert the collection id.getDetails().values() into int[] for passing to getDetails(int id,int... ids) instead of calling getDetails(Collection<Integer> idCollection).
I could cast the collection to Integer[] as below,
(Integer[])id.getDetails().values().toArray()
I did not find a way to cast Collection to int[].
Any suggestions would be of great help.
I already referred to some of the existing questions but did not succeed to solve my issue:
Conversion of collection to int array
Convert java.util.Collections to Integer array
Collection to Integer[]
When you need to get a result of type Integer[], you have to provide a function as an argument while calling toArray(), there's no need to apply casting (if you're not passing a parameter toArray() returns an array Object[]).
Integer[] arr = id.getDetails().values().toArray(Integer[]::new);
Collection to int[]
There's no way convert a Collection of Integer type or an array Integer[] into an array int[] directly. It's not possible to obtain one from another simply by doing casting, these types are not compatible.
You have to iterate over the source and populate the newly created int[] array. It can be done either "manually" using a loop, or in a more convenient way with streams, the overall approach doesn't change.
That's how it can be done using Stream API:
int[] arr = id.getDetails().values().stream() // Stream<Integer> - stream of objects
.mapToInt(Integer::intValue) // IntStream - stream of primitives
.toArray();
You can't cast Collection<Integer> to int[], but you can create the array:
int[] values = id.getDetails().values().stream()
.mapToInt(n -> n)
.toArray();
An aside... this code:
if (!idCollection.contains(id)) {
idCollection.add(id);
}
May be changed to just:
idCollection.add(id);
because idCollection is a Set and that's how sets work. It matters not that it's declared as a Collection; it is a Set.
I have added some Integers to an ArrayList of object type, and want it to be sorted. My code looks like:
List<Object> list = new ArrayList<Object>();
list.add(24);
list.add(2);
list.add(4);
Collections.sort(list); // getting error here
System.out.println("Sorted list ");
for (Object e : list) {
System.out.println(e);
}
I got the following compile-time error:
error : should implement java.lang.Compareble <? super java.lang.Object>
How should I resolve this issue?
Object class doesn't implement Comparable interface. If you're sure you're adding Integer you can use code as below and then perform sorting.
List<Integer> list = new ArrayList<Integer>();
From sort() method docs
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).
The error message that your IDE generating is
The inferred type Object is not a valid substitute for the bounded parameter >
Which means that the Objects being put in that List must implement Comparable interface to accept in sort() method.
Object class not implementing comparable interface, hence the error which you are seeing.
Using Object of type in Generic is not advisable and use specific type. Since you are adding all integers to the list just change your declaration to
List<Object> intList = new ArrayList<Object>();
If any other object of your own type, just implement comparable interface in that class or pass a custom comparator as a second parameter to sort.
Since you have declared your list to have the type List<Object>, you are able to store anything into it, be it comparable or not.
The generic method Collections.sort(List) has a type signature which requires that your list has an element type which implement the Comparable interface, which ensures that all elements can be compared to each other, and it tells the sort method how to compare these elements, as said interface contains the method which can be called to compared two elements. In other words, it does not accept a List that could contain anything.
So is your case, you should change the declaration to
List<Integer> list = new ArrayList<>();
as you are only adding Integer objects. Integer is a type which implements Comparable as integer values have a natural order.
Note that you can simplify your code:
List<Integer> list = Arrays.asList(24, 2, 4);
Collections.sort(list);
System.out.println("Sorted list "+list);
The list returned by Arrays.asList does not support changing its size, but reordering the elements is supported, hence you can sort that list.
As a side note, in the rare case, you have a List<Object> whose type you can’t change, but you know for sure that it contains only elements being naturally comparable to each other, you can circumvent the type constraint of Collection.sort:
Collections.sort(list, null);
The method Collections.sort(List, Comparator) supports arbitrary element types as the second parameter tells how to compare them. As a special case, a comparator of null mandates natural order, but null passes every type check. But, of course, using this trick will backfire when the assumption about the elements is wrong.
Generally, you should ensure that the element type as declared at compile-type is appropriate for the desired operation. Here, using List<Integer> when the list is supposed to contain Integers is the right way.
Instead of doing Collections.sort(list), you can loop through the array and sort the objects from least to greatest.
you can do it like this:
for(int i = 0; i < intList.size(); i++) {
// if an integer is larger than any of the ones after it in the array, switch them.
}
the Object class does not implement the Comperable interface, hence it gives you this error. You should rather define it as List<Integer>, or define a custom comperator class and pass it as an aditional Argument.
public class Comp<T> implements Comparator<T>{
#Override
public int compare(T o1, T o2) {
if(o1 instanceof Integer && o2 instanceof Integer) {
int a = (Integer) o1;
int b = (Integer) o2;
return a-b;
}
return 0;
}
}
// Call it as
Collections.sort(list, new Comp<Object>());
But you may run in several Problems while using a List of Objects and a custom Comperator, since you could add everyting to this list.
What it comes down to is I'm attempting to construct a List<T> from the java.util.List package based on an enumerator, but here's the catch- I don't want the first value to be in the list. The way that I've come up with doing this... Well... It can't be a good thing.
Here's the code I'm using:
Arrays.asList(Arrays.asList(MyEnum.values()).remove(0));
This effectively creates a List<> from my enum, and removes the first value, then tries to create another list with the created list.
This may actually be the correct way to do it, but just looking at it is screaming "Inefficient". I showed it to a few people on a forum that I'm a member of and they all said how ugly it was, and laughed; However not a single one of them could/would provide a better way to go about doing it.
I don't think that code is really ugly or inefficient. The bigger problem is it doesn't work because the list returned by Arrays.asList is backed by the underlying array, and so it has a fixed size.
You can use subList instead of remove to get it working:
List<MyEnum> list = Arrays.asList(MyEnum.values());
list = list.subList(1, list.size());
This means that the resulting list actually consists of two list objects (the asList and its subList), which may or may not bother you. However, you can create a flat ArrayList from the resulting list:
list = new ArrayList<>(list);
If you'd rather minimize object allocation, loop the values and add them to a single list directly:
MyEnum[] values = MyEnum.values();
List<MyEnum> list = new ArrayList<>(values.length - 1);
for (int i = 1; i < values.length; i++)
list.add(values[i]);
How about:
Arrays.asList(MyEnum.values()).subList(1, MyEnum.values().length);
Are you sure you can't (wouldn't want to) use MyEnum.values and treat your first element differently where it's used?
public enum Enums {
first,
b,
c,
d,
e,
f;
public boolean isFirst(Enums e) {
return e == first;
}
}
This would work:
List<T> enums = Arrays.asList(Arrays.copyOfRange(MyEnum.values(), 1, MyEnum.values().length - 1));
Or java 8:
Arrays.stream(MyEnum.values()).collect(Collectors.toList()).subList(1, MyEnum.values() - 1);
Hmmm... not much better .
I have an Array of primitives, for example for int, int[] foo. It might be a small sized one, or not.
int foo[] = {1,2,3,4,5,6,7,8,9,0};
What is the best way to create an Iterable<Integer> from it?
Iterable<Integer> fooBar = convert(foo);
Notes:
Please do not answer using loops (unless you can give a good explanation on how the compiler do something smart about them?)
Also note that
int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);
Will not even compile
Type mismatch: cannot convert from List<int[]> to List<Integer>
Also check
Why is an array not assignable to Iterable?
before answering.
Also, if you use some library (e.g., Guava), please explain why this is the Best. ( Because its from Google is not a complete answer :P )
Last, since there seems to be a homework about that, avoid posting homeworkish code.
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
List<Integer> list = Arrays.asList(foo);
// or
Iterable<Integer> iterable = Arrays.asList(foo);
Though you need to use an Integer array (not an int array) for this to work.
For primitives, you can use guava:
Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
<type>jar</type>
</dependency>
For Java8 with lambdas: (Inspired by Jin Kwon's answer)
final int[] arr = { 1, 2, 3 };
final Iterable<Integer> i1 = () -> Arrays.stream(arr).iterator();
final Iterable<Integer> i2 = () -> IntStream.of(arr).iterator();
final Iterable<Integer> i3 = () -> IntStream.of(arr).boxed().iterator();
just my 2 cents:
final int a[] = {1,2,3};
java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int pos=0;
public boolean hasNext() {
return a.length>pos;
}
public Integer next() {
return a[pos++];
}
public void remove() {
throw new UnsupportedOperationException("Cannot remove an element of an array.");
}
};
}
};
With Java 8, you can do this.
final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();
Guava provides the adapter you want as Int.asList(). There is an equivalent for each primitive type in the associated class, e.g., Booleans for boolean, etc.
int foo[] = {1,2,3,4,5,6,7,8,9,0};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
System.out.println(i);
}
The suggestions above to use Arrays.asList won't work, even if they compile because you get an Iterator<int[]> rather than Iterator<Integer>. What happens is that rather than creating a list backed by your array, you created a 1-element list of arrays, containing your array.
In Java 8 or later, Iterable is a functional interface returns Iterator.
So you can do this.
static Iterable<Integer> convert(int[] array) {
return () -> Arrays.stream(array).iterator();
}
and
int[] array = {1, 2, 3};
Iterable<Integer> iterable = convert(array);
for (int i : iterable)
System.out.println(i);
output:
1
2
3
I had the same problem and solved it like this:
final YourType[] yourArray = ...;
return new Iterable<YourType>() {
public Iterator<YourType> iterator() {
return Iterators.forArray(yourArray); // Iterators is a Google guava utility
}
}
The iterator itself is a lazy UnmodifiableIterator but that's exactly what I needed.
First of all, I can only agree that Arrays.asList(T...) is clearly the best solution for Wrapper types or arrays with non-primtive datatypes. This method calls a constructor of a simple private static AbstractList implementation in the Arrays class which basically saves the given array reference as field and simulates a list by overriding the needed methods.
If you can choose between a primtive type or a Wrapper type for your array, I would use the Wrapper type for such situations but of course, it's not always useful or required.
There would be only two possibilities you can do:
1) You can create a class with a static method for each primitive datatype array (boolean, byte, short, int, long, char, float, double returning an Iterable<WrapperType>. These methods would use anonymous classes of Iterator (besides Iterable) which are allowed to contain the reference of the comprising method's argument (for example an int[]) as field in order to implement the methods.
-> This approach is performant and saves you memory (except for the memory of the newly created methods, even though, using Arrays.asList() would take memory in the same way)
2) Since arrays don't have methods (as to be read on the side you linked) they can't provide an Iterator instance either. If you really are too lazy to write new classes, you must use an instance of an already existing class that implements Iterable because there is no other way around than instantiating Iterable or a subtype.
The ONLY way to create an existing Collection derivative implementing Iterable is to use a loop (except you use anonymous classes as described above) or you instantiate an Iterable implementing class whose constructor allows a primtive type array (because Object[] doesn't allow arrays with primitive type elements) but as far as I know, the Java API doesn't feature a class like that.The reason for the loop can be explained easily:for each Collection you need Objects and primtive datatypes aren't objects. Objects are much bigger than primitive types so that they require additional data which must be generated for each element of the primitive type array. That means if two ways of three (using Arrays.asList(T...) or using an existing Collection) require an aggregate of objects, you need to create for each primitive value of your int[] array the wrapper object. The third way would use the array as is and use it in an anonymous class as I think it's preferable due to fast performance.
There is also a third strategy using an Object as argument for the method where you want to use the array or Iterable and it would require type checks to figure out which type the argument has, however I wouldn't recommend it at all as you usually need to consider that the Object hasn't always the required type and that you need seperate code for certain cases.
In conclusion, it's the fault of Java's problematic Generic Type system which doesn't allow to use primitive types as generic type which would save a lot of code by using simply Arrays.asList(T...). So you need to program for each primitive type array, you need, such a method (which basically makes no difference to the memory used by a C++ program which would create for each used type argument a seperate method.
You can use IterableOf from Cactoos:
Iterable<String> names = new IterableOf<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
Then, you can turn it into a list using ListOf:
List<String> names = new ListOf<>(
new IterableOf<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
)
);
Or simply this:
List<String> names = new ListOf<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
While a similar answer has already been sort of posted, I think the reason to use the new PrimitiveIterator.OfInt was not clear. A good solution is to use Java 8 PrimitiveIterator since it's specialized for primitive int types (and avoids the extra boxing/unboxing penalty):
int[] arr = {1,2,3};
// If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
while (iterator.hasNext()) {
System.out.println(iterator.nextInt());
// Use nextInt() instead of next() here to avoid extra boxing penalty
}
Ref: https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html
In java8 IntSteam stream can be boxed to stream of Integers.
public static Iterable<Integer> toIterable(int[] ints) {
return IntStream.of(ints).boxed().collect(Collectors.toList());
}
I think performance matters based on the size of the array.
I have a hashMap. Each "Value"is going to be a a list which will be mapped later on with my "Key"s. List is desired to look like this:
[length,time][length,time][length,time]
For example:
Key{srcAddr=x, dstAddr=y, srcPort=12345, dstPort=80}
value{(6523,0.001),(124,0.05), () , (), ...}
I just wonder how can I have a two-col arrayList.
package myclassifier;
import java.util.ArrayList;
public class FlowStatics {
int packetLength;
double timeArrival;
public FlowStatics(int pLength, double tArrival)
{
this.packetLength = pLength;
this.timeArrival = tArrival;
}
}
and here is how I used it:
final ArrayList<FlowStatics> staticsArray = new ArrayList<FlowStatics>();
final HashMap<Flows, ArrayList> myHashMap = new HashMap<Flows, ArrayList>();
FlowStatics flowStatics = new FlowStatics(packetLength,timeArrival);
staticsArray.add(flowStatics);
myHashMap.put(flows, staticsArray);
and here is the part that I am reading it:
Iterator<Flows> iterator = myHashMap.keySet().iterator();
while(iterator.hasNext()){
Flows key = iterator.next();
ArrayList value = myHashMap.get(key);
System.out.println("Fows"+key+"----------"+"Statics"+ value);
Well, your FlowStatics is the correct solution
List<FlowStatics> will give you the "two-column array list".
Update: as of your update, myHashMap.put(flows, flowStatics); is wrong. You are this putting an individual pair, rather than a list in the map. You should use:
staticsArray.add(flowStatics);
myHashMap.put(flows, staticsArray);
A List<E> is an abstraction for a homogeneous list of elements whose type is E. There are some restrictions (e.g. no primitives), but conceptually the type E can be defined to be whatever you want.
Suppose there's an abstraction of Pair<L,R>. Then a List<Pair<L,R>> is still a list of some E, but now that E is a Pair<L,R>. So it's still a "one-column" list, but each element in the list is a "pair", so it's sort of a "two-column" list.
Note that you don't always need a generic Pair<L,R>. Any type E that properly encapsulates all the information can be used in a List<E>.
And by the way, you can have a List<List<E>> too.
See also
Wikipedia/Encapsulation
Related questions
What is the equivalent of the C++ Pair<L,R> in Java?
List of Lists of Lists
Returning values analogy
Often people ask "How can I return two values in Java?". The answer is analogous. You return one value, a new type which encapsulates both information.
So instead of:
// attempt to return two values
// DOES NOT COMPILE
return "James Bond";
return "007";
You do:
return new SecretAgent("James Bond", "007");
Related questions
Using a java method to return multiple values?