Kategorien
Dev Note Java Programming Languages

DEV-NOTES|Java: Surprising import findings

You might not know that the order of static imports and ordinary imports is crucial. I stumbled upon a code snippet using a static import from a static inner class, during some codes research for a work project. Trying out that code ends up with a compiler error, saying that a standard class from the JDK was not found.

For the sake of simplicity and to ease understanding I provide a similar small example to illustrate the issue:

package de.mindcrimeilab.strange.staticimport;

// this does not work using JDK 8, but in JDK 9 and 10, comment this
// and uncomment the corresponding import below to make it work
// in JDK 8
import static de.mindcrimeilab.strange.staticimport.StrangeIntSorter.FlexibleIntegerComparator.DESC;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.StringJoiner;
import java.util.stream.Collectors;

// uncomment this to make it work with JDK 8
//import static de.mindcrimeilab.strange.staticimport.StrangeIntSorter.FlexibleIntegerComparator.DESC;

/**
 * 
 * @author Michael Engelhardt <me@mindcrime-ilab.de>
 *
 */
public class StrangeIntSorter {
	
	/**
	 * Sort a list of random integers.
	 * 
	 * @param {@code FlexibleIntegerComparator.DESC} sort in descending order,
	 *        {@code FlexibleIntegerComparator.ASC} sort in ascending order
	 * @return sorted list
	 */
	public List<Integer> sortRandomIntList(int order) {
		List<Integer> intList = new Random().ints(0, 1024).limit(10).boxed().collect(Collectors.toList());
		Collections.sort(intList, new FlexibleIntegerComparator(order));
		return intList;
	}

	/**
	 * Simple comparator implementation letting you choose the sorting order during
	 * creation.
	 * 
	 * @author Michael Engelhardt <me@mindcrime-ilab.de>
	 *
	 */
	static class FlexibleIntegerComparator implements Comparator<Integer> {
		static final int ASC = 1;
		static final int DESC = -1;

		private final int order;

		FlexibleIntegerComparator(int order) {
			this.order = order;
		}

		@Override
		public int compare(Integer o1, Integer o2) {
			return o1.compareTo(o2) * order;
		}
	}

	/**
	 * Main method.
	 * 
	 * @param args
	 */
	public static void main(String... args) {
		System.out.println("Sorting some ints: ");
		StrangeIntSorter strangeIntSorter = new StrangeIntSorter();
		List<Integer> sortedRandomIntList = strangeIntSorter.sortRandomIntList(DESC);

		StringJoiner joiner = new StringJoiner(",");
		sortedRandomIntList.forEach(num -> joiner.add(num.toString()));

		System.out.println(joiner.toString());
	}
}

On Java 8 you will get a compiler error:

:45: error: cannot find symbol
        static class FlexibleIntegerComparator implements Comparator<Integer> {
                                                          ^
  symbol:   class Comparator
  location: class StrangeIntSorter

That is very surprising, because that is one of the standard interfaces provided by the Java SDK. Curiously it will work if you run it from inside Eclipse. More over Eclipse puts that static import on top of the class if you use the ‚organize imports‘ option. You can fix this error by putting the static import statement below the non-static import statements.

According to the Java Language Specification JLS 7.5 Import Declarations the order of static and non static imports could be mixed. A compilation unit consists beside others out of a number of ImportDeclarations JLS 7.3:

CompilationUnit:
    PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt

ImportDeclarations:
    ImportDeclaration
    ImportDeclarations ImportDeclaration

TypeDeclarations:
    TypeDeclaration
    TypeDeclarations TypeDeclaration

Whereas each ImportDeclaration might be either an import or a static import JLS 7.5:

ImportDeclaration:
    SingleTypeImportDeclaration
    TypeImportOnDemandDeclaration
    SingleStaticImportDeclaration
    StaticImportOnDemandDeclaration

Thankfully that problem is solved by later versions of the JDK. On JDK 9 as well as on JDK 10 the code compiles without any errors regardless if you are putting the static imports on top or below. To take it the right way it does depend on the position of the static import that way, that you have to import all necessary symbols to compile the originating class of the static import.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

drei + 11 =