2

I want to make a shallow copy of a List I get returned by a method call (it's public List getScanResults () from Android, see http://developer.android.com/reference/android/net/wifi/WifiManager.html#getScanResults%28%29). The problem is, clone() is not defined on the List interface, but only on concrete classes like ArrayList - however I don't know what getScanResults() uses internally, so I can't just simply cast it or am I wrong about this? I then thought of something like

anExistingList.add(getScanResults());

but getScanResults() seems to return null instead of an empty list if there's nothing to return, so that is also no option. When I would do something like

if(getScanResults() != null)
    anExistingList.add(getScanResults());

the return value of getScanResults() could change between the first code line and the second one, therefore it could pass the "not equals null" condition first and then be null in the second line or am I wrong about this?

So, how would I make a shallow copy of the return value of getScanResults() or just formulating my goal: Getting a value from getScanResults() and make sure it doesn't change while I am working with it?

Thanks for any hint :-) (I guess I am just understanding something wrong)

stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270

3 Answers3

1

Look here. java.util.Collections provides the static method copy to copy the contents from one list to another.

Constantinius
  • 34,183
  • 8
  • 77
  • 85
  • Unfortunately, if getScanResults() returns null, Collections.copy causes a NullPointerException ): – stefan.at.kotlin May 11 '11 at 16:13
  • Then you propably hav to call `getScanResults()`, save it to a temporary variable, check if it is null (just as in your example) and then proceed with the copying. – Constantinius May 11 '11 at 16:23
1

All well behaved collections have copy constructors. So create an instance of the type of list you want, depending on your needs (e.g. fast indexing or efficient removal of some elements).

In this case, you have to do a little bit more to handle the inconvenience of a possible null. So something like this:

/**
 * @return a copy of the original; an empty list if original is null.
 */
public static <T> List<T> randomAccessibleCopy(List<T> original) {
    return (null == original) 
             ? Collections.<T>emptyList() 
             : new ArrayList<T>(original);
}

Now you can call this method with the results of the underlying API that returns the list.

Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
  • But I can only create the target List and copy() means providing a copy not copying from another List (getScanResults() in that case) ? – stefan.at.kotlin May 11 '11 at 16:17
  • @stefan, I've edited the post to show how to deal with null. But reading your other comments, it looks like you are concerned about concurrent changes, too. If the underlying list returned is 'live', the API you are using needs to provide some synchronization semantics too. – Dilum Ranatunga May 11 '11 at 16:28
0
if(getScanResults() != null)
    anExistingList.add(getScanResults());

should be

List x = getScanResults();
if(x != null)
    anExistingList.add(x);

As the method now is called only once, it can't change in the meantime.

Pindatjuh
  • 10,550
  • 1
  • 41
  • 68
  • But x is just holding a reference to the return value of getScanResults() and the value getScanResults() returns could change without getScanResults() being called, e.g. if the value getScanResults() return is a class variable, it could internally change. – stefan.at.kotlin May 11 '11 at 16:15
  • A "getter" should not return a result that is modified. Especially when it's called "results". The API says: *Return the results of the latest access point scan.* This means, the *last access point scan* when the method was called. So the List will never get modified by the API. This can be used safely. – Pindatjuh May 14 '11 at 16:19
  • N.B.: Even if the List changes; it can never change the reference to an object, from the `x` variable to null; that's illegal in Java. It may, however, change it's internal state, but that is not a problem when checking for null. So even if my above comment is wrong (I doubt that very much), it still would be correct code. – Pindatjuh May 14 '11 at 16:20
  • So: whatever implementation there is at `getScanResults()` the above code will give a copy of the list. Either, this is a copy of the value given at `List x = getScanResult`, or, when the implementation modifies the given list, at `anExistingList.add(x)`. – Pindatjuh May 14 '11 at 16:23
  • I *hihgly doubt* that the API modifies the list; as the `List` class in Java is thread unsafe, it would mean that some clients would break in very rare conditions. If it wanted to modify the returned list, it should return a thread-safe version of the `List`, or say in the documentation that the returned `List` is thread-safe. Neither of these cases, hence you can assume the `List` will never be modified when it's returned by the call. – Pindatjuh May 14 '11 at 16:24