True Gem: running multiple Ant targets

Really, IDEA never ceases to amaze me. Even after years using it I still find new, pleasant features every now and then. Today I found out that I can run multiple ant targets in a single step.

And the best part is: I found out that just because I thought I could do it, and IDEA did exactly what I expected it to do. I selected multiple targets (holding CTRL) and pressed the run button. To my delight, IDEA ran all the targets I selected, in the order I selected them. Superb. Fantastic. This level of usability and expectation is what really makes IDEA the best product of it's kind.

I'm feeling like someone who's been married for decades, wakes up in the morning and finds out some new trait about his wife that makes him loves her more each day :) Ok, enough with the sugar :P

14 comments
Comment actions Permalink

wow - I was missing that, but did not dare to try it! :)

0
Comment actions Permalink


Very cool, but what I really want is to be able to to select multiples (as you describe), click a button, and have the sequence of targets appear as a "combined target" under the "Build" menu. That way common sequences of ant targets could be made repeatable, and wouldn't require opening the Ant toolwindow (always a hassle). That would rule. I had a tracker item for that back in the day. I'll enter a request in Jira. The common reward for a job well done is, after all, another job.

--Dave Griffith

0
Comment actions Permalink

I have the Ant tool window mapped to ALT+2 on my keymap, and can't live without it. So much more useful than the commander :)

0
Comment actions Permalink

ALT-9 here, not that I ever use the commander. And I have F9, Shift F9 and Ctrl F9 mapped to my most commonly used targets.

Ant all the way :)

0
Comment actions Permalink

I'm feeling like someone who's been married for
decades, wakes up in the morning and finds out some
new trait about his wife that makes him loves her
more each day :) Ok, enough with the sugar :P


The difference is that with IDEA this actually happens every now and then!! ;)

0
Comment actions Permalink

Dave Griffith wrote:

Very cool, but what I really want is to be able to to select multiples (as you describe), click a button, and have the sequence of targets appear as a "combined target" under the "Build" menu. That way common sequences of ant targets could be made repeatable, and wouldn't require opening the Ant toolwindow (always a hassle). That would rule. I had a tracker item for that back in the day. I'll enter a request in Jira. The common reward for a job well done is, after all, another job.

--Dave Griffith


Sounds almost like an Ant Refactoring: Extract Combined Target. Such
things would be cool.

--
Rob Harwood
Software Developer
JetBrains Inc.
http://www.jetbrains.com
"Develop with pleasure!"

0
Comment actions Permalink

On Thu, 24 Feb 2005 at 12:51 GMT, Rob Harwood (JetBrains) wrote:

Sounds almost like an Ant Refactoring: Extract Combined Target. Such
things would be cool.


I was thinking the other day it'd be cool to have an Extract Target
refactoring, select a block of ant tasks, extract to newTargetFoo, create
the new target, and replace the existing code with an <antcall/> or such,
passing in any required parameters.

If the extracted contents where at the start of the target, it could
simple be added to the depends="" attribute. mmmmmm.

0
Comment actions Permalink

You'll laugh I do find gems in IDEA myself as well.
Today's one was unusual usage of Dave's replace == with .equals intention.
I've intentionally written something like "a == b" and then used intention
to convert it to a.equals(b). Thus it seems there's no need to write .equals()
calls manually at all since typing == usually much simpler! Same conserns
tough StringBuffer.append() calls. Who bothers coding new StringBuffer("x
= ").append(x).append(", y = ").append(y).append(", z = ").append(z) instead
of "x = " + x + ", y = " + y + ", z = " + z and use AltEnterEnter :)

Thanks Dave!

-


Maxim Shafirov
http://www.jetbrains.com
"Develop with pleasure!"



0
Comment actions Permalink

I didn't know about that "Replace + with StringBuffer.append()"

That is pretty handy. But I wonder with JDK 1.4 and JDK 5.
0 compiler, do you can any performance benefit from the
StringBuffer( ) vs. string concatenation. Couldn't the
compiler automatically optimized it?

Also, in JDK 5.0, they recommend you change all
StringBuffer to StringBuilder. Here is the blurb from the
javasoft site.

"StringBuilder class - The addition of a new class
StringBuilder that works essentially as an unsynchronized
StringBuffer for performance enhancement. You should
replace all StringBuffer uses with StringBuilder unless you
need the synchronization (which you almost certainly don't).
StringBuilder is almost always faster than StringBuffer."
http://java.sun.com/j2se/1.5.0/docs/guide/performance/speed.
html

If the compiler is automatically converting the string
concatenation to StringBuilder() calls, you could be making
the code slower by converting to StringBuffer.

One advantage both StringBuffer() and StringBuilder() have
is that you can preallocate a larger buffer space to avoid
reallocation.

For example, take this line of code:

String deviceInfo;
String deviceName;

String data = START_STRING1
+ deviceInfo
+ "')\""
+ START_STRING2
+ '>'
+ deviceName
+ "</a>";

after the "Replace + with StringBuffer.append()" I get

String data = new StringBuffer().append(START_STRING1)
.append(deviceInfo)
.append("')\"")
.append(START_STRING2)
.append('>')
.append((deviceInfo)
.append("</a>")
.toString();

It might also help to automatically initialize the default
size of the StringBuffer,e.g.

new StringBuffer(START_STRING1.length() + START_STRING2.length()deviceName.length()deviceInfo.length()+32);

But I'm wondering if I left it as simple string
concatenation, then the compiler could be doing this
conversion automatically for me? And it might be using
StringBuilder() and it might be setting the size correctly
based on above formula.

Anyway, I think this Intention should replace with
StringBuilder() instead of StringBuffer() in JDK 5.0.

0
Comment actions Permalink

I've been meaning to change this inspection from StringBuffer to StringBuilder if StringBuilder is available. That'll probably happen with the next couple of EAP's.

--Dave Griffith

0
Comment actions Permalink

FYI

I compiled the string concatenation example:

String data = START_STRING1
+ deviceInfo
+ "')\""
+ START_STRING2
+ '>'
+ deviceName
+ "</a>";

with JDK 5.0 compiler and then decompiled it back to source:

String data = (new StringBuilder()).append("Start").
append(deviceInfo).
append("')\"").
append("Start2").
append('>').
append(deviceName).
append("</a>").toString();


0
Comment actions Permalink

Alex wrote:

FYI

I compiled the string concatenation example:

String data = START_STRING1
+ deviceInfo
+ "')\""
+ START_STRING2
+ '>'
+ deviceName
+ "</a>";

with JDK 5.0 compiler and then decompiled it back to source:

String data = (new StringBuilder()).append("Start").
append(deviceInfo).
append("')\"").
append("Start2").
append('>').
append(deviceName).
append("</a>").toString();


Amazing how little optimization java compilers actually do. Jikes
shortens that a bit and produces the bytecode equivalent of this:

String data = new StringBuffer("Start").append(deviceInfo).
append("')\"Start2>").
append(deviceName).
append("</a>").toString();

Too bad it can't be used with jdk1.5's new features.

Bas

0
Comment actions Permalink

as far as I remember, JDK 1.3 already compiled single statement string concatenations into StringBuffer.append calls.

But the real performance gain is when concatenating in loops, and the compiler didn't replace those.
for example

String s = "anything";
for ( ...) {
s+= "something";
}
This was compiled into :
String s = "anything";
for ( ...) {
s=new StringBuffer(s).append("something");
}

In fact, string concatenation doesn't exist in the JVM, everything is done via StringBuffer.appends

0
Comment actions Permalink

Just because this horse hasn't been quite beaten yet:

I compiled the following code using 1.5 javac.

public static void concat1() {
StringBuffer sb = new StringBuffer();
sb.append("test1").append("test2");
}

public static void concat2() {
StringBuffer sb = new StringBuffer();
sb.append("test1" + "test1");
}


And then used javap to look at the resultant bytecode:


public static void concat1();
Code:
0: new #2; //class java/lang/StringBuffer
3: dup
4: invokespecial #3; //Method java/lang/StringBuffer."":()V 7: astore_0 8: aload_0 9: ldc #4; //String test1 11: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 14: ldc #6; //String test2 16: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 19: pop 20: return public static void concat2(); Code: 0: new #2; //class java/lang/StringBuffer 3: dup 4: invokespecial #3; //Method java/lang/StringBuffer."":()V 7: astore_0 8: aload_0 9: ldc #7; //String test1test1 11: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 14: pop 15: return This didn't tell me squat, since the compiler intelligently just made a new string literal for the combined strings in contact2();. I tried again this time using a method call to retreive the strings: public static void concat3() { StringBuffer sb = new StringBuffer(); sb.append(getString()).append(getString()); } public static void concat4() { StringBuffer sb = new StringBuffer(); sb.append(getString() + getString()); } This resulted in the following with javap: public static void concat3(); Code: 0: new #3; //class java/lang/StringBuffer 3: dup 4: invokespecial #4; //Method java/lang/StringBuffer."":()V 7: astore_0 8: aload_0 9: invokestatic #9; //Method getString:()Ljava/lang/String; 12: invokevirtual #6; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 15: invokestatic #9; //Method getString:()Ljava/lang/String; 18: invokevirtual #6; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 21: pop 22: return public static void concat4(); Code: 0: new #3; //class java/lang/StringBuffer 3: dup 4: invokespecial #4; //Method java/lang/StringBuffer."":()V 7: astore_0 8: aload_0 9: new #10; //class java/lang/StringBuilder 12: dup 13: invokespecial #11; //Method java/lang/StringBuilder."]]>":()V
16: invokestatic #9; //Method getString:()Ljava/lang/String;
19: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: invokestatic #9; //Method getString:()Ljava/lang/String;
25: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #13; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: invokevirtual #6; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
34: pop
35: return


So it looks like 1.5 now looks to StringBuilder internally (as opposed to StringBuffer). It's still really impossible to tell which is "faster", as the jvm compiler will apply who knows what optimizations if it ever gets compiled.

I always figured the bytecode for contact3() and concat4() would end up the same, but I guess not. I could have sworn it was so in earlier java versions.

The moral of the story is write code thats readable and ignore such underlying issues. Assume the compiler is smarter then you. Not because it neccessarily is, but because I may have to read your code someday. :)

In any case:

Dear intellij developers. Stop making java so easy to play with. I don't get enough sunlight as it is.

:)




0

Please sign in to leave a comment.