Closure folding in IntelliJ IDEA 9 (Maia)

IntelliJ IDEA 9 will bring you a clearer code reading experience with the support of folding for probably the most verbose Java constructions — anonymous classes. In IntelliJ IDEA 9 you will have an option to quickly collapse them to compact, easy to read form and back with a single keystroke.



Ordinary anonymous class syntax display



Closures folding enabled


EAP users will be, as always, the first to try it out when we release the very first Maia builds, so make sure you’re on the list and watch for the news!

Comments below can no longer be edited.

20 Responses to Closure folding in IntelliJ IDEA 9 (Maia)

  1. Avatar

    Alexey Efimov says:

    March 10, 2009

    Great, but please add also easy API for such foldings. I have idea to create plugin for folding our functional classes into compact form such as:
    List mappedList = myList map { a -> a.toString()};

  2. Avatar

    Peter Gromov says:

    March 10, 2009

    Alexey, the API is really simple

  3. Avatar

    Gilles Philippart says:

    March 10, 2009

    This reminds me of a very interesting IntelliJ plugin written by Alain Ravet, the Camouflage plugin (http://plugins.intellij.net/plugin/?id=57).
    Maybe it was a bit overlooked, but it had very nice ideas about making the code more readable ! You should take a look at it 🙂

  4. Avatar

    Igor Sereda says:

    March 10, 2009

    Hmmm, would you please consider leaving out “ActionListener(ActionEvent e)” as well? Because it doesn’t really bear useful info and might be a little longer: “DynamicPropertyChangeListener<Map>(ChangeEvent<Map> e)”.

    Maybe just:
    myNodeBox.addActionListener({ onNodeChanged(); });

  5. Avatar

    Igor Sereda says:

    March 10, 2009

    i’m sorry, can’t figure out how to write code in these comments. in my example i meant DynamicPropertyChangeListener<Map<DynamicPropertyKey,DynamicPropertyValue>>(ChangeEvent<Map<DynamicPropertyKey,DynamicPropertyValue>> e), but i think you get the idea

  6. Avatar

    mark says:

    March 10, 2009

    Again IntelliJ steals eclipse plugin’s feature. its classic.

  7. Avatar

    Peter Gromov says:

    March 11, 2009

    Gilles, thanks for the advice! Actually we have more new foldings. We’ll blog about them in near future.

    Igor, in fact the generic class parameters aren’t displayed in placeholder text, so it won’t be so long. I can make an option, but from my personal experience, not having the class name appear in placeholder makes me constantly looking inside to know, which class it is.

    Mark, this feature was done independently of eclipse plugin and earlier than we’ve heard of that. It just wasn’t announced. Anyway, I don’t think that having a feature similar to Eclipse’s is somehow bad.

  8. Avatar

    Michael Parmeley says:

    March 12, 2009

    @Mark That is odd you accuse IntelliJ of copying a Eclipse plugin. Eclipse was started as a cheap imitation of IntelliJ and as far as I can tell it still remains a cheap an inferior copy of IntelliJ. It just copies everything Jetbrains has added to IntelliJ.

    Eclipse may do some of its own innovation now, but it certainly didn’t start out that way.

  9. Avatar

    Igor Sereda says:

    March 16, 2009


    I think if you display “ActionEvent” instead of “ActionEvent<T>” in the placeholder, that would be misleading. But I see what you mean. I think it makes sense to display type when needed and parameters when needed.

    For example:

    1. “ActionEvent e” is used, so we need to display it:

    myNodeBox.addActionListener(ActionListener(ActionEvent e) { onNodeChanged(e); });

    2. ActionEvent is not used, listener type is inferred:

    myNodeBox.addActionListener({ onNodeChanged(); });

    or at least (without type inference)

    myNodeBox.addActionListener(ActionListener(…) { onNodeChanged(); });

    3. Type cannot be inferred:

    Object r = Runnable { doWork(); };

  10. Avatar

    Peter Gromov says:

    March 23, 2009


    Actually the user can type inside these folded closures, so not displaying the parameters probably won’t be correct since they can be still referenced and completed inside the closure. As for generics, instead of hiding them I can shorten them to (if the corresponding folding is enabled). As I’ve already said, I’m strictly against hiding base class name, but this can be made an option if there are many proponents (probably a JIRA issue?).

  11. Avatar

    Ray Cromwell says:

    May 12, 2009

    Why not adopt Neal Gafter’s BGGA closures syntax?

    Then you’d write:

    addActionListener({ActionEvent e => onNodeChanged()});

    Better yet, since some people might prefer the CICE or FCM proposals, why not make it a preference or pluggable?

  12. Avatar

    Ray Cromwell says:

    May 12, 2009

    BTW, this mechanism seems incredibly powerful and could resolve a whole range of issues with Java. It would allow each programmer to visualize source in a way that makes them most productive while keeping the source in a neutral format (i.e. Java). It seems like a sort of Intentional Programming.

    I hope you guys take this and run with it. No need to wait on Sun/Oracle/JCP. You can add support for Closures, Type Inferencing, Operator Overloading, etc now. The editor can be taught to visualize these in a succinct way (e.g. BigDecimal.add() = ‘+’) while preserving source code compatibility on disk.

  13. Avatar

    Jim Popovich says:

    June 14, 2009

    Expanding on this, you should add a config flag to “graphically” distinguish = form ==
    using = means draw (glpyh) onNodeChanged()} | (glyph) ActionListener );

    the | reads AS meaning the {} closure created AS a new ActionListener

    so that if you had many you could see

    pretend that there are 2 of the ActionListener classes

    addActionListener( {ActionEvent e –>(glpyh) onNodeChanged()} | (glyph) ActionListener );

    addActionListener( {ActionEvent e –>(glpyh) onSuperNodeChanged()} | (glyph) ActionListenerSuper );

    And you can use your “show me the Camel’s” flag to just render the camels, which is very concise.

    addActionListener( {AE e –>(glpyh) onNodeChanged()} | (glyph) AL );

    addActionListener( {AE e –>(glpyh) onSuperNodeChanged()} | (glyph) ALS );

  14. Avatar

    Jim Popovich says:

    June 14, 2009

    the first paragraph some how was garbled when submitted on the web site,

    in long hand so it does not get garbled.

    suggest that we can display different single glph chars for EQUAL vs DOUBLE EQUALS vs NOT EQUALS and you see the NOT EQUALS like a mathematical not-equal with a diagonal slash. the single EQUAL is drawn as a LEFT ARROW we use a RIGHT arrow in closure params separator and a graphic equals means equals = = .
    you could have a really long graphical like 3 or 4 equals to swap in method .equals
    so that you can see

    mini = = = = me

    rather than mini.equals(me)

  15. Avatar

    Peter Gromov says:

    June 15, 2009

    Jim, the equals folding sounds reasonable, could you file a JIRA issue for it?

    As for closures, I don’t completely understand which glyphs you want to display. | meaning ‘as’ also seems strange for a Java person.

  16. Avatar

    Aaron Knauf says:

    June 19, 2009

    This sounds like a fantastic feature. Lots of good ideas in these comments. Key things that I would like: let me concentrate on the code – not the boilerplate. Don’t show me the “new EventListener(){ onClick(MouseEvent e){} }” bit, unless necessary to disambiguate. Just show me the code that I need to write. e.g.

    addListener(…{…(MouseEvent e){

    I would avoid trying to fold anonymous classes into a closure syntax that resembles some other language, like ruby, or C#, or one of the proposals for java closures (which James Gosling reckons are off the cards now anyway). There just isn’t any one of those syntaxes that has a dominant support base. Use the folding syntax that you already use throughout IDEA, which all of your users are already familiar with.

  17. Avatar

    Piotr Gabryanczyk says:

    June 26, 2009

    Have a look at closures project.

    It does simple closures in java and with IntelliJ “inject language” feature it works brilliantly!

    Following things are now possible in java:

    each(asList(“a”,”b”,”c”), “print ‘Element ‘+it+’n'”)
    will print to the System.out:

    Element a
    Element b
    Element c

    find(asList(“ab”, “abc”, “bc”, “bcd”), “it =~ /.*a.*/; “);
    => “ab”

    findAll(asList(1,2,3,4,5,6,7), “it % 2 == 0”)
    => [2,4,6]

    findAll(asList(“ab”, “abc”, “bc”, “bcd”), “it =~ /.*a.*/”)
    => [“ab”, “abc”]

    collect(asList(1,2,3), “it *it”)
    => [1,4,9]

    any(asList(“ab”, “abc”, “bc”, “bcd”), “it =~ /bc/; “)
    => true

    any(asList(“ab”, “abc”, “bc”, “bcd”), “it =~ /bcde/; “)

    every(asList(“ab”, “abc”, “bc”, “bcd”), “it.length() > 0”)
    => true

    every(asList(“ab”, “abc”, “bc”, “bcd”), “it =~ /.*a.*/; “)
    => false

  18. Avatar

    Vadim Pesochinskiy says:

    July 7, 2009

    I have following code which have to retry something action. I downloaded Maia in anticipation of tada moment, but nothing happens.

    new Retry(3,5000).run(new Retry.If(new Class[] {RemoteException.class} ) {
    public void exec() throws Exception {
    ; // do something that throws RemoteException

    I was kinda hoping to see this:

    new Retry(3,5000).run(new Retry.If(…) {
    ; // do something that throws RemoteException

    So, where is the trick 🙁 ? I am bitterly disappointed. Make me smile!

  19. Avatar

    Derek Greer says:

    May 13, 2011

    This is a very old thread, but in playing with IntelliJ Community Edition 9.0, the folding doesn’t look anything like this. It basically collapses down where the body reads { … }. In the example presented in the article, the anonymous noise is collapsed, but the body of the method is revealed which is what I’m looking for. Is this not how it works?

  20. Avatar

    Peter Gromov says:

    May 16, 2011

    Derek, it’s not enabled by default. You need to go to the Folding settings and check ‘Closures’ there

Discover more