Amnesiac Java: language features I forgot existed 19

Posted by Michael Studman Fri, 27 Aug 2004 03:00:00 GMT

I've been developing in Java for pretty much since Java 1.0. While working on the ANTLR Java 5 grammar I was suprised to rediscover some features of the language I'd just plain forgot.

First up, while working on annotation array initialisers, I was pleasantly reminded that the final element of a regular array can have a trailing comma:

    String[] foo =
        new String[]
        {
            "qwerty1",
            "qwerty2",
            "qwerty3",
        };

This is a nice little convenience for when you need to expand or contract the array elements in the initialiser - it means you don't have to fiddle with the final element to make sure there is no trailing comma.

Later I was reminded that interfaces may be package protected. For some reason i'd deluded myself into thinking interfaces could only be public:

    package foo;
    interface Bar {}
    ...
    package foo2;
    class Bar2
    {
       foo.Bar b;
           //compilation error: foo.Bar can't
           //be accessed from outside its package
    }

Duh! How could I have lived without that one? I often complained to co-workers that I couldn't do this - by their response they obviously didn't know you could either.

Finally, I was recently reminded that you can use the .class 'field' on primitive types:

    Class c = int.class;

I've long been aware of this 'field' on regular classes and interfaces (e.g. String.class) but when faced with the need to get the class of a primitve type I'd use the helper fields (e.g. Integer.TYPE). This forgotten feature is nicely consistent.

I use quotations around the word field here because it's not really a field, just a few grains of syntactic sugar (decompile a class that uses the .class 'field' to see what I mean).

What's your forgotten language feature?

Trackbacks

Use the following link to trackback from your own site:
http://www.michaelstudman.com/fullfathomfive/articles/trackback/25

Comments
  1. Avatar
    Anonymous Fri, 27 Aug 2004 23:28:32 GMT

    "transient"

  2. Avatar
    Paul Holser Sat, 28 Aug 2004 03:10:46 GMT

    Instance initializers -- I've been exploiting these lately to abbreviate list initialization (in unit tests only):

    List triple = new ArrayList(3) { { add("a"); add("b"); add("c"); } };

    and option parser initialization:

    OptionParser parser = new OptionParser("ab:c::") { { requiresArg("outfile"); optionalArg("verbose"); noArg("help"); } };

  3. Avatar
    Chris Thiessen Sat, 28 Aug 2004 03:27:30 GMT

    Local classes. Somehow I didn't pick up on them until years after I first learned Java.

    One use for them is manual closures, which other local and anonymous inner classes modify a shared value, not just use finals.

    int method() { class Closure() { int value; } final Closure c = new Closure(); for(int i=0; i<10; i++) new Object() { { c.value = 10; } }; return c.value; }

  4. Avatar
    kevin Sat, 28 Aug 2004 10:22:21 GMT

    I'm not sure if I'm reading your example wrong, Chris, due to the simplification, but how is "final Closure c = new Closure()" any better than "final int[] c = new int[1]"?

  5. Avatar
    kevin Sat, 28 Aug 2004 11:00:09 GMT

    ThreadLocal seems to get the stepchild treatment. It's been the perfect answer to a couple of vexing problems of mine.

    It also surprises me to see people on my team dealing with issues of / vs. \ in pathnames, or \n vs. \r\n in text files, when they could just use java.io.File and PrintWriter/BufferedReader to deal with all that crap automatically. These probably aren't the sort of answers you had in mind.

  6. Avatar
    J Yu Sat, 28 Aug 2004 12:13:40 GMT
        String[] foo =
        {
            &quot;qwerty1&quot;,
            &quot;qwerty2&quot;,
            &quot;qwerty3&quot;,
        };
    
  7. Avatar
    Gabriel Mihalache Sat, 28 Aug 2004 20:12:54 GMT

    If you don't need them, it's ok not to know them. If you DO need something you research it and then you know... otherwise you'll soon forget them again.

  8. Avatar
    Anonymous Sun, 29 Aug 2004 08:23:47 GMT

    strictfp

  9. Avatar
    Paul Kilroy Mon, 30 Aug 2004 07:33:31 GMT

    I believe the trailing comma in your array initializers is not allowed by Jikes. I'm not sure who's right though.

  10. Avatar
    Ranbato Tue, 31 Aug 2004 02:51:24 GMT

    How about javax.swing.ProgressMonitor?

  11. Avatar
    Michael Studman Tue, 31 Aug 2004 09:35:17 GMT

    Hi Paul.

    I believe javac is correct. Fron the JLS 2nd Edition:

    ArrayInitializer: { VariableInitializersopt ,opt }

    VariableInitializers: VariableInitializer VariableInitializers , VariableInitializer

    VariableInitializer: Expression ArrayInitializer

    Michael.

  12. Avatar
    Michael Studman Tue, 31 Aug 2004 09:39:15 GMT

    Hi J Yu,

    String[] foo = { "qwerty1", "qwerty2", "qwerty3", };

    It's strange, but I always feel more comfortable with:

    String[] foo = new String[] { "qwerty1", "qwerty2", "qwerty3", }

    I know, it's more verbose and less clear but maybe it marries well with my writing style. ;)

    Michael.

  13. Avatar
    Michael Studman Tue, 31 Aug 2004 09:56:55 GMT

    Hi Paul Holser,

    List triple = new ArrayList(3) { { add("a"); add("b"); add("c"); } };

    I can why this appeals. The only pitfall, as I'm sure you're aware, is that if you use this syntax multiple times then you'll be creating a new (inner) class for each usage.

    So what makes it more appealing to:

    List triple = new ArrayList(3); add("a"); add("b"); add("c");

    I think it's that the first snippet of code guarantees that upon construction, the ArrayList is pre-loaded with values when first seen in the current thread's current frame whereas the last snippet, at least conceptually, allows for the new instance to be initially empty. It's a moot point since the code as written won't expose the not-completely-initialised instance to anybody but itself, but it feels better knowing that it can't happen.

    Syntactic security blanket, perhaps?

    Michael.

  14. Avatar
    Tu Nam Tue, 31 Aug 2004 20:23:19 GMT

    I just have use a bit about abstract class :

    abstract class Test1 { public abstract void testing1(); public void test2() { testing1(); } } public class Testing { public static void main(String args[]) { Test1 t1=new Test1() { public void testing1() { System.out.println("Hello Test1 "); }
    }; t1.test2(); } } It print out "Hello Test1" ; this anonymous abstract class implementing above seems like the implement of anonymous interface ActionListener.

  15. Avatar
    Paul Holser Wed, 01 Sep 2004 03:01:36 GMT

    List triple = new ArrayList(3) { { add("a"); add("b"); add("c"); } }; vs. List triple = new ArrayList(3); triple.add("a"); triple.add("b"); triple.add("c"); vs. List triple = Arrays.asList(new String[]{"a", "b", "c"});

    The last two just seem clunkier to me. I wouldn't use this anon-inner-plus-instance-initializer style of list initialization willy-nilly, and certainly not in production code--but it's cool not to have to repeat the receiver of add() or do the gymnastics routine of using the java.util helpers.

  16. Avatar
    Jamie Wed, 01 Sep 2004 04:30:44 GMT

    How is #3 "clunkier" than #1?

  17. Avatar
    Anki Thu, 02 Sep 2004 07:59:06 GMT

    Just found in Intellij Forums, thought of sharing it. http://intellij.net/forums/thread.jsp?nav=false&forum=27&thread=107222&start=0&msRange=15

    Quick summary class Test { static void TEST() {

    } }

    Test t = null; t.TEST(); //Works fine :) see the link for explanation by Greg Lucas

  18. Avatar
    Anonymous Sat, 04 Sep 2004 03:05:00 GMT

    Quick summary class Test { static void TEST() {

    } }

    Test t = null; t.TEST(); //Works fine :) see the link for explanation by Greg Lucas
    Perhap cause it's a static class so JVM always have a reference to that class ( weak or else I don't remember ) so though assigned null but JVM wasn't collect it . Well I have to go to watch the explain.

  19. Avatar
    Achim Thu, 03 Mar 2005 06:36:25 GMT

    I nearly forgot about:

    int[][]iArr[]; // type is int[][][]

    This is xtremely sloppy in Java. There is no clean separation between typeSpec and IDENT.

    And then... int[][] iarr[]={{{1,2},{3,4}},{{5,6},{7}}};...

    Let's forget about that.

Comments are closed for this article