While not high on the list of “Things Java Could Do Better,” there’s plenty of ways we could reimagine the humble import
. For most of us, the IDE handles our imports (thank you very much), so we don’t spend a whole lot of time thinking about them. Imports are a rather arcane way to make the compiler gods happy. I think they could look a little nicer, don’t you? Let’s look at your average set of import statements (taken from the Spring Framework, PortletWrappingController.java):
package com.implementsblog.post;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventPortlet;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.ResourceServingPortlet;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.NoHandlerFoundException;
import org.springframework.web.portlet.context.PortletConfigAware;
import org.springframework.web.portlet.context.PortletContextAware;
import org.springframework.web.portlet.util.PortletUtils;
First, what’s up with the package
statement? It’s redundant since the file structure dictates the package (or is it the other way around?). (I’d really love the package
keyword to be repurposed to mean “package-private access,” but that argument is for another post.) Next, why so many imports? Why not let import
take an array or something similar?
import {
java.util.Collections,
java.util.Enumeration,
java.util.HashSet,
java.util.LinkedHashMap,
java.util.Locale,
java.util.Map,
java.util.ResourceBundle,
javax.portlet.ActionRequest,
javax.portlet.ActionResponse,
javax.portlet.EventPortlet,
javax.portlet.EventRequest,
javax.portlet.EventResponse,
javax.portlet.Portlet,
javax.portlet.PortletConfig,
javax.portlet.PortletContext,
javax.portlet.PortletSession,
javax.portlet.RenderRequest,
javax.portlet.RenderResponse,
javax.portlet.ResourceRequest,
javax.portlet.ResourceResponse,
javax.portlet.ResourceServingPortlet,
javax.xml.XMLConstants,
javax.xml.namespace.QName,
org.springframework.beans.factory.BeanNameAware,
org.springframework.beans.factory.DisposableBean,
org.springframework.beans.factory.InitializingBean,
org.springframework.web.portlet.ModelAndView,
org.springframework.web.portlet.NoHandlerFoundException,
org.springframework.web.portlet.context.PortletConfigAware,
org.springframework.web.portlet.context.PortletContextAware,
org.springframework.web.portlet.util.PortletUtils
}
That looks better. Let’s take this idea to the extreme and nest them like a directory tree:
import {
java.util {
Collections,
Enumeration,
HashSet,
LinkedHashMap,
Locale,
Map,
ResourceBundle
},
javax {
portlet {
ActionRequest,
ActionResponse,
EventPortlet,
EventRequest,
EventResponse,
Portlet,
PortletConfig,
PortletContext,
PortletSession,
RenderRequest,
RenderResponse,
ResourceRequest,
ResourceResponse,
ResourceServingPortlet
},
xml {
XMLConstants,
namespace.QName
}
},
org.springframework {
beans.factory {
BeanNameAware,
DisposableBean,
InitializingBean
}
web.portlet {
context {
PortletConfigAware,
PortletContextAware
},
ModelAndView,
NoHandlerFoundException,
util.PortletUtils
}
}
}
Part of me says this is more elegant, but part of me says it’s too hard to read. Our IDEs could help us by highlighting the path of the selected import; something like this:
org.springframework {
beans.factory {
BeanNameAware,
DisposableBean,
InitializingBean
}
web.portlet {
context {
PortletConfigAware,
PortletContextAware
},
ModelAndView, <--Cursor is here
NoHandlerFoundException,
util.PortletUtils
}
}
Nah, that’s too weird, lets go back to one import per line. Since import
s are only for the compiler, what if we didn’t have to state an import unless it was ambiguous? If I have a class named ReallyUniqueClassName
you’re telling me the compiler can’t figure out the fully qualified name for me? I don’t buy it. But if I use List
, it could be either java.util.List
or java.awt.List
, and I should be able to put import util.List
at the top of my file. Listing each and every import makes sense if you’re not using and IDE, but you are using and IDE, aren’t you?
One final thought: isn’t it weird that packages don’t nest? For example, the package cool
has no relation whatsoever to cool.beans
. Even the Java Spec uses the word “subpackage” all over the place, but technically a package and its subpackage have no special treatmeant, they’re just like any two packages. This is despite the fact that
- Package names must match folders
- the folder
beans/
is nested insidecool/
How would we structure our code if cool.beans
was in the package cool
? For starters, we could achieve a kind of “module privacy” by putting package-private classes in the root package of our project (somewhere like com.company.project
). We wouldn’t be able to seal our packages, but is that such a bad thing? (You can still seal JARs, at least.)
But what do I care, I let the IDE do my importing for me, right?