Mark is a graph advocate and field engineer for Neo Technology, the company behind the Neo4j graph database. As a field engineer, Mark helps customers embrace graph data and Neo4j building sophisticated solutions to challenging data problems. When he's not with customers Mark is a developer on Neo4j and writes his experiences of being a graphista on a popular blog at http://markhneedham.com/blog. He tweets at @markhneedham. Mark is a DZone MVB and is not an employee of DZone and has posted 532 posts at DZone. You can read more from them at their website. View Full User Profile

Java: Fooled by java.util.Arrays.asList

02.15.2012
| 6800 views |
  • submit to reddit

I’ve been playing around with the boilerpipe code base by writing some tests around it to check my understanding but ran into an interesting problem using java.util.Arrays.asList to pass a list into one of the functions.

I was testing the BlockProximityFusion class which is used to merge together adjacent text blocks.

I started off calling that class like this:

import static java.util.Arrays.asList;
 
@Test
public void willCallBlockProximityFustion() throws Exception {    
    TextDocument document = new TextDocument(asList(contentBlock("some words"), contentBlock("followed by more words")));
    BlockProximityFusion.MAX_DISTANCE_1.process(document);
}
 
private TextBlock contentBlock(String words) {
    TextBlock textBlock = new TextBlock(words, new BitSet(), wordCount(words), 0, 0, 0, 0);
    textBlock.setIsContent(true);
    return textBlock;
}

Which blows up like this:

java.lang.UnsupportedOperationException
	at java.util.AbstractList.remove(AbstractList.java:144)
	at java.util.AbstractList$Itr.remove(AbstractList.java:360)
	at de.l3s.boilerpipe.filters.heuristics.BlockProximityFusion.process(BlockProximityFusion.java:115)
	at de.l3s.boilerpipe.filters.heuristics.BlockProximityFusionTest.willCallBlockProximityFustion(BlockProximityFusionTest.java:63)

The code around that area is trying to remove an element from an iterator…

                if (ok) {
                    prevBlock.mergeNext(block);
                    it.remove();
                    changes = true;
                } else {

…which was created from the list that we passed into the constructor of TextDocument:

        for (Iterator<TextBlock> it = textBlocks.listIterator(offset); it

The remove method is not implemented on the list created by ‘Arrays.asList’ which is weird since I thought it created an ArrayList which does implement remove!

I’ve now learnt that the ArrayList created by ‘Arrays.asList’ is actually a private inner class of Arrays and doesn’t implement the remove method!

Who knew…

 

From http://www.markhneedham.com/blog/2012/02/11/java-fooled-by-java-util-arrays-aslist/

Published at DZone with permission of Mark Needham, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Carlos Hoces replied on Wed, 2012/02/15 - 3:34am

This is the actual code as found in JavaSE 1.7u2 for Arrays.asList

 @SafeVarargs

    public static <T> List<T> asList(T... a) {

        return new ArrayList<>(a);

    } 

Which JavaSE version were you using? 

Lance Semmens replied on Wed, 2012/02/15 - 3:47am

I can remember having troubles with Arrays.asList() too. From memory I was using java 1.4 and the resultant list was not Serializable.

Ziomal Kowalski replied on Wed, 2012/02/15 - 4:50am in response to: Carlos Hoces

You should look closer at the code - the ArrayList used here is not java.util.ArrayList, but java.util.Arrays.ArrayList - a private static class defined inside the java.util.Arrays. Anyway, the documentation for Arrays.asList states clearly, that the returned list has a fixed-size: "Returns a fixed-size list backed by the specified array."

Mladen Girazovski replied on Wed, 2012/02/15 - 4:52am

Who knew...

 Those who read the JavaDoc ;)

Returns a fixed-size list backed by the specified array.

There is a difference if a method start with to.. vs. as.., the latter is just another representation of the original data, arrays are fixed size.

 

 

Adam Derda replied on Wed, 2012/02/15 - 9:28am

The list returned by Arrays.asList method is unmodifable - you can't add or remove any element. If you need to be able to modify it, you can create a new list and initialize it with the list returned by Arrays.asList: 

String[] arr = {"aa", "bb"};
List<String> lst = new ArrayList<String>(Arrays.asList(arr));  

Jesse Long replied on Fri, 2012/02/24 - 10:33am

Iterator.remove() is an optional operation.

Neal Johnson replied on Sun, 2012/03/04 - 4:21am

The documentation does hint at this, "Returns a fixed-size list backed by the specified array". The only way to delete from the array would be a resize the original array, this would then be reflected in the returned list.

However the documentation only mentions writes are updated to the array, and not resizing either by add or removing elements. In fact a further clue to its behaviour is, "This method also provides a convenient way to create a fixed-size list...". I guess sometimes the documentation is not as clear as it could be.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.