Showing posts with label jdk 5. Show all posts
Showing posts with label jdk 5. Show all posts

Sunday, April 19, 2009

concurrentmodificationexception or: how I learned to stop worrying and loved for-each loop as it is

Few days ago, I got a ConcurrentModificationException out of nowhere while I was iterating through a list and removing elements from it. I remember doing this thing and not getting any exception. I delved a little bit and realized that the exception is thrown because of my misuse of for-each loop (introduced in jdk 5). Its developers noted:
Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel.


For-each loop creates and hides the iterator, so when you try to remove an element using the list itself you'll get ConcurrentModificationException because you have to do the removing and adding through the iterator. So the code below will throw ConcurrentModificationException.

/*
integerList is an ArrayList
with Integer objects as elements
*/

for(Integer integer : integerList){
if(integer.intValue()%2 == 0) // remove even elements
integerList.remove(integer);
}


You can fix your error by not using for-each loop. For instance, you can define your iterator and work with it or you can iterate through the array list and do the add/remove directly from the list.

First one's code:


Iterator iterator = integerList.iterator(); // create the iterator
while(iterator.hasNext()){
Integer integer = iterator.next(); // take the element
if(integer.intValue()%2 == 0)
iterator.remove(); // remove using the iterator
}


Second approach's code:



for(int i=0 ; i < integerList.size(); i++){
Integer integer = integerList.get(i); // take the element
if(integer.intValue() %2 == 0){
// remove from the list
integerList.remove(i);
/*
decrease the index by one, so
that we won't skip any elements
after the element left-shifting which
occurs after each removal.
*/

i--;
}
}

Tuesday, November 18, 2008

scanner class

Java 5 introduced Scanner class which has a functionality similar to the Reader in addition to the StringTokenizer class. Scanner can read input from a File, InputStream and ReadableByteChannel and can tokenize this data. It is more powerful than StringTokenizer, because it can parse primitives directly instead of taking them as String and parsing them to the corresponding primitive type.
Assume that we want to take the user input which consists of two Strings (e.g. name and last name) and an integer (e.g. student number).
Let's see how Scanner class works:
First we will link scanner to some input source.

// I link Scanner to System input.
Scanner scanner = new Scanner(System.in);

Then Scanner will take the input from user and parse the input values to desired variables.

String name = scanner.next();
String lastName = scanner.next();
int studentNumber = scanner.nextInt();
// above I parsed anything I needed, below I'll close my Scanner.
scanner.close();
/*Scanner closed. If the input source implements Closeable interface, it will be closed after that method call.*/


It is also possible to parse numbers with base other than decimal.

scanner.useRadix(2); // I'm setting Scanner to take a binary number as input
int number = scanner.nextInt();
// assume that the input was "101" which's "5" in decimal base
// then number is now "5".

Sunday, November 16, 2008

cooler for-loops

JDK 5 offers an interesting enhancement for for-loops. With the new feature, for-loops are less error-prone and with a higher readability. You can convert your for-loop from
for(int i=0; i < integerArray.length; i++) {
System.out.println( integerArray[i] );
}

to
// read below as int i "in" integerArray
for(int i : integerArray){
System.out.println( i );
}

Better, huh? Same stuff works with object arrays too.

Tuesday, October 21, 2008

varargs in java 5

I'm going to talk about one of the minor enhancements of Java 5; Varargs. Normally, if you are going to pass an arbitrary number of elements (object or primitive type) to a function, you would put them into an array and then pass the array to the function.
Assuming we have a concat() function such as

String concat(String[] tokens){
String result = "";
for(int i=0; i<tokens.length; i++){
result += tokens[i];
}
return result;
}

We will put all the Strings to be concatanated in an array and pass them to concat(). i.e. concat( new String[]{"come", "on", "eileen"} ) .

With Varargs, it is now possible to skip the array creation and pass the elements (again, object or primitive type) directly to the method. You change the concat() function so that it can accept them. String concat(String[] tokens){ becomes String concat(String... tokens){ and now you're free to pass any number of elements to concat() function without worrying about an array.
i.e. concat("come", "on", "eileen"); concat("dexymidnightrunners");