简体   繁体   中英

Java 8 compatibility issue: How to convert Object array to Subtype List in Java 8?

So I had a program that worked fine on Java 7 but it fails to compile with an error in Java 8. So, I went through Java Compatibility issues and I think I found out the reason (Or did I? http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7144506 ) . I want to know if there's a short an efficient way to replicate what my original code snippet does with Java 8. Here's a program to represent the situation. In my code there's a setter method that does the job of populating the array and I have no control on how it's populated.

import java.util.List;
import java.util.Arrays;

public class HelloWorld{
    public static void main(String []args){
        B someObject=new B();
        List<A> a = someObject.getA() == null ? Collections.EMPTY_LIST : Arrays.asList(someObject.getA());
        for ( A item : a ) {
            System.out.println(item.value);
        }
    }
}

class A{
    String value;
    public A(String value){
        this.value = value;
    }
}

class B{
    Object[] getA(){
        Object arr[]= new Object[4];
        arr[0]=new A("hello");
        arr[1]=new A("mello");
        arr[2]=new A("jello");
        arr[3]=new A("cello");
        return arr;
    }
}

The error of course being:

HelloWorld.java:8: error: incompatible types: bad type in conditional expression                                                                                                
        List<A> a = someObject.getA() == null ? Collections.EMPTY_LIST : Arrays.asList(someObject.getA());                                                                      
                                                                                      ^                                                                                         
    inference variable T has incompatible bounds                                                                                                                                
      equality constraints: A                                                                                                                                                   
      lower bounds: Object                                                                                                                                                      
  where T is a type-variable:                                                                                                                                                   
    T extends Object declared in method <T>asList(T...)                                                                                                                         
Note: HelloWorld.java uses unchecked or unsafe operations.                                                                                                                      
Note: Recompile with -Xlint:unchecked for details.                                                                                                                              
1 error                     

I need a (preferrably one line/elegant) alternative method which is also efficient to accomplish the same.

EDIT: To clarify. I cannot control what class B returns to me. Nor can I modify class A in any way (I don't think that could help in any case). I can only control what HelloWorld does.

If you have no access to B, but are sure that you get A's, you could try something like this:

Object[] objArray = someObject.getA(); // omit calling getA() twice
List<A> a = objArray == null ? Collections.emptyList() :
                 Stream.of(objArray)
                         .map(o -> (A) o) // or place your transform function in here
                         .collect(Collectors.toList());

As @JBNizet pointed out: the really easiest, but unsafe and therefore not really recommended solution, is to just add a List -cast:

List<A> a = objArray == null ? Collections.emptyList() : (List)Arrays.asList(objArray);

If you are unsure, about what is in the array, you should rather use the following to filter out only the A's:

List<A> a = objArray == null ? Collections.emptyList() :
                 Stream.of(objArray)
                         .filter(o -> o instanceof A)
                         .map(o -> (A) o) // or place your transform function in here
                         .collect(Collectors.toList());

or the same with method references:

List<A> a = objArray == null ? Collections.emptyList() :
                 Stream.of(objArray)
                         .filter(A.class::isInstance)
                         .map(A.class::cast) // or place your transform function in here
                         .collect(Collectors.toList());

EDIT: added objArray to omit calling getA() twice as seen on @Holger's answer. Calling it twice might be more expensive than all the rest of the proposed solutions.

The safest solution is to copy the array into an array of the correct type, ie

Object[] array = someObject.getA();
List<A> a = array==null? Collections.emptyList():
    Arrays.asList(Arrays.copyOf(array, array.length, A[].class));

with Java 8, there is the option to use the Stream API instead, which is only slightly shorter:

Object[] array = someObject.getA();
List<A> a = array==null? Collections.emptyList():
    Arrays.asList(Arrays.stream(array).toArray(A[]::new));

If you worry about the array copying costs, well, in your original code you invoked getA() twice, imposing even higher costs than just a plain array copy. The above solutions fix that.

Performing unchecked operations “because I know what I'm doing” rarely pays off. In this specific case, you would just move the costs from the list creation to the place where the list will be used.

Object[] array = example.getLabelCodes();

Converting Object array to List..

List<String> stringArray = Arrays.asList(Arrays.stream(array).toArray(String[]::new));

Converting List back to Object Array..

Object[] objectArray = stringArray.toArray();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM