There is a good amount of stuff to get excited about in this release.
- Try-with-resources-Catch-Block [0]
- Fork/Join libraries from Doug Lea (author of Executor framework) [1]
- Inferred/Simpler generics in declarations (should have been in Java 5)
- NIO2, brand new/robust filesystem APIs [2]
- NIO2, treat ZIP/JAR files like directories of files for R/W [3]
- SDP support [4]
- String-in-switch (NOTE: check on performance implications of this for tight loops)
NOTE: Read through "COMPILATION" section here for details [6]
- Elliptic curve cryptography (when normal curves just don't cut it)
- Underscores in numbers (e.g. int million = 1_000_000;)
- XRender pipeline on Linux (Swing/Java2D rendering get a big boost)
- New sound synthesizer (replaces a proprietary lib that wasn't OS)
- XML stack finally got updated across the board.
- InvokeDynamic (already talked about numerous times below)
- Other Swing stuff I'm not all that pumped about.
I think the most exciting items are:
1. Try-with-resources
2. NIO2 filesystem API
3. InvokeDynamic
Features that got pushed to 8 (next year) that will be really exciting:
- Modular programming (super packages? think OSGi-lite)
- Syntactic Sugar: Collection literals
List<String> people = {"Frank", "Mary", "Satan"};
- Closures
- Modularization of the JDK (JDK gets broken into core modules)
And one that I can't get confirmation on if it's in 7 or got pushed, index-access for List and Maps [5]:
I understand that a lot of people don't find Java sexy any more, that is understandable, it has become a platform for what seems like a lot of next-series of languages.
That being said, I've been working with Java since 1998 and still love it. I know people get a big kick out of writing code with no exception handlers and no curly braces, and programming is a creative/artistic process so you have to do what feels good... but none of that stuff ever bothered me.
> And one that I can't get confirmation on if it's in 7 or got pushed, index-access for List and Maps
I just tried it out, it didn't get added to 7.
> String-in-switch (NOTE: check on performance implications of this for tight loops)
I haven't checked the performance, but I tried decompiling a String switch statement:
String test = "asdf";
switch (test) {
case "sss":
System.out.println("sss");
break;
case "asdf":
System.out.println("asdf");
break;
}
That decompiles to:
switch(test.hashCode()) {
case 114195:
if(test.equals("sss"))
byte0 = 0;
break;
case 3003444:
if(test.equals("asdf"))
byte0 = 1;
break;
}
switch(byte0) {
case 0: // '\0'
System.out.println("sss");
break;
case 1: // '\001'
System.out.println("asdf");
break;
}
So it's one switch on the String's hashcode, with calls to equals to verify that the string is a match (and an if/else if/else block if you have multiple strings in the switch that have the same hashcode), assigning the result to a temp variable, and then a switch on a temp variable to execute your code.
Really appreciate you going through the trouble to do that and post the results so we don't need any hand-waving.
This looks the same as the original proposal -- using the hashCode and final verification via equals.
So in a typical case scenario you have the 1-time calculation of the String's hashCode (which is then cached by java.lang.String) and the two method calls.
.equals() is the only thing that could get away from you performance wise, because unless string1 == string2 or are different lengths, you fall into a char-by-char comparison loop.
That could be a shitty surprise if you have a bunch of constants like "SAVE, RMVE, DELT, INST, UPDT" and don't realize what you are causing to happen under the covers.
I'd be curious (now) what actually happens with using Enums in switch statements to see what kind of hidden code is actually getting executed.
## UPDATE: It looks like using Enums ends up getting translated to:
switch(enum.ordinal())
calls followed up goto statements to the case labels. So enums should be practically just as performant as constant numeric values except for the method call.
If the JVM is smart enough to replace the calls to 'ordinal' with the constant return value, then it should be right on par with using numerical constants which would be sweet and make using the strategy outlined in that link possibly a nice performant alternative to normal Enum use.
The .equals() still shouldn't be much of a problem. If you've got a bunch of constants like you gave, they will probably all have different hashcodes so you don't have to compare against all of them.
I checked what happens when you use an enum, and it generates some funky code. It creates an anonymous inner class with a static initializer for an array of ints. It uses the ordinal value to assign a sequential number starting with one. Then the switch statement is on intArray[theEnum.ordinal()], and the case statements start with 1. Here's the code:
class Test2{
public static void main(String[] args) {
MyEnum en = MyEnum.ONE;
switch (en) {
case ONE:
System.out.println("one"); break;
case TWO:
System.out.println("two"); break;
default:
System.out.println("default");
}
}
}
enum MyEnum {
ONE, TWO, THREE;
}
Decompiled (after being compiled with jdk1.7.0):
public static void main(String args[])
{
MyEnum myenum = MyEnum.ONE;
static class _cls1
{
static final int $SwitchMap$MyEnum[];
static
{
$SwitchMap$MyEnum = new int[MyEnum.values().length];
try
{
$SwitchMap$MyEnum[MyEnum.ONE.ordinal()] = 1;
}
catch(NoSuchFieldError nosuchfielderror) { }
try
{
$SwitchMap$MyEnum[MyEnum.TWO.ordinal()] = 2;
}
catch(NoSuchFieldError nosuchfielderror1) { }
}
}
switch(_cls1.$SwitchMap$MyEnum[myenum.ordinal()])
{
case 1: // '\001'
System.out.println("one");
break;
case 2: // '\002'
System.out.println("two");
break;
default:
System.out.println("default");
break;
}
}
I wonder why it doesn't just switch on the ordinal directly. It's also worth noting that it has to make an array for MyEnum.values().length. This means if you have an enum with a lot of values, you're wasting a lot of memory (especially since it creates this array every class you use a switch in).
I tried with an enum with 40 values, and it didn't switch to a map. Maybe there's some higher threshold where it would switch to a map instead (but again, I don't understand why it wouldn't switch on ordinal() directly).
Good point about equals, I'm just thinking in a tight render loop (like in a game engine or something equally as sensitive) even with the diff hash codes you are dropping through to a char-to-char comparison IN the off chance that your two strings are the same length.
I'll be the first to admit those are pretty slim odds, but it's always fun to dig up these little performance things hidden in the JVM and store them away for later use in some interesting project.
Nice decompile with the enums... no idea what's with the array either; another hidden gem to at least be aware of.
This is alot like when autoboxing came out. New Java people thought int i and Integer ii were the same when used in different settings, not realizing that under the covers Integer.valueOf(i) and ii.intValue() are getting generated.
It's great if valueOf is returning a cached value (-127 to 128) but beyond that you are just object-creating all over the place.
Working on SJXP (xml parser layer that sits ontop of Pull Parser to make it like XPath, but super fast) I did some HPROF and found my use of path hashcode lookups in a Map<Integer, String> was generating millions of Objects.
So I moved to an Integer cache that holds the Integer object generated from the hashCode() and re-uses it as needed.
Ended up dropping the overhead (CPU and memory) of the library below everything in native XPP to where it adds almost no overhead.
Anyway -- thanks for diving deep with me on that, we have two new tricks up our sleeves ;)
I wonder why it doesn't just switch on the ordinal directly.
I don't know how JVM bytecode works, or if it's even possible to assign discontiguous ordinal values, but in C compiled to x86 assembly language, a switch statement on (mostly-)contiguous values can be converted into a jump table. If there are large gaps in the switch values, either you have a lot of wasted space in the jump table, you have multiple jump tables, or you fall back to if/elseif/etc-style code.
It would make more sense to me to assign the contiguous integer values during the construction of the Enum, but maybe that doesn't work when Java 7 code tries to use an Enum compiled with Java 6 or earlier.
> I don't know how JVM bytecode works, or if it's even possible to assign discontiguous ordinal values
That was my first thought as well, but I double checked and the ordinal() method is final, so you're guaranteed not to get anything other than continuous values for your enums.
> in C compiled to x86 assembly language, a switch statement on (mostly-)contiguous values can be converted into a jump table
Ah, this is probably the intention. The JVM can probably optimize the switch. I just checked it, and when there are multiple switch statements in a class only using a few values in an enum, it tries to make them all sequential in the switch, that's why it uses the array. I guess it's just a mistake (or lazy coding) that it always makes the array size TheEnum.values().length rather than how many it's actually going to use.
Oh sweet jesus finally collection literals. Why did it take more than 10 years to decide to bring in something so convenient? One reason I sometimes find Java repulsive is the fact that it takes so much redundant code to do something so simple. Why do they hold back on such syntactic sugar?
For version 8, I think it is a stretch to say that it will support 'closures'. [0]
The closures that are proposed are more like a bolted on psuedo solution, basically syntactic sugar that makes the language more complex. You can only use them in SAM (Single Abstract Method) situations. If only they just added a simple lisp like lambda expression...
I fail to see how the lambdas, when added, will make the language more complex.
Here's an example: given a list of persons, we'd like to extract all the adults.
Compare the good ol' way of doing things in Java:
Notice how the logic (filtering a list) gets drowned in irrelevant details such as creating the result list, iterating over the list, and accumulating the matching elements.
The alternative (the poor man's functional Java) with libs like Google collections would look like:
A one-liner, where the core logic (comparing the age to 18) clearly stands out.
The auto conversions of lambdas to SAM types is a spark of genius if you ask me. But I'm not happy with the decision of not implementing structural types in Java. IMO, this will lead to a Cambrian explosion in the number of SAM types, types like Mapper<S, T>, Reducer, Folder, Filter or Predicate, plus the custom types added by various frameworks.
One other great feature in JDK8 will be defender methods which will allow interfaces to carry default behavior for methods. This will be the mechanism for adding default behavior in the collection libraries without breaking classes that extend them. It will also have a lot of great use cases in new library development.
I wasn't even aware of that proposal, just found these examples[1] and love the idea.
Sort of in the same vein as static imports (as far as usability) but has a really nice added side effect of exporting a default impl from an interface that can be overridden.
Syntactic Sugar: Collection literals
List<String> people = {"Frank", "Mary", "Satan"};
I find it breathtaking this isn't core yet. I was writing test fixture support code for 1.4 to easily and DRYly generate lists of up to 10 items, which required 10 copy-paste functions each with a different number of arguments. 1.5 came along and made it possible to easily do it with one function thanks to varargs, but it's 6 years later and still no collection literals!
I don't think anyone would disagree with you; we definitely went through a stagnation of Java between 6 and 7 where it seemed Sun was trying to find it's footing with Java, trying to not sink the company, trying to be bought up, trying to figure out where Netbeans fit in the scheme of everything, etc. etc.
It is like the Java world hit the 'pause' button on really ambitious stuff for a few years and the only things that got into releases were the laser-sharp-focused features that the teams needed no variation on. They knew exactly what the feature was, where to take it and when to ship it.
I think it was for the better, because now there is all this pent up energy getting reinjected into the platform and we'll see 8 next year with the rest of all these goodies and hopefully 9/10 2 years after that.
Pretty good recovery IMO. At least it didn't languish and die a horrible death or something.
JSR 310 is not Joda for Java 8 (or 7). It's by Joda's author and uses a very similar API, but it's a cleanroom implementation and not compatible with Joda: over time, Stephen Colebourne (Joda lead dev) found core issues in Joda, and JSR-310 is the occasion to use the lessons learned from Joda.
That being said, I've been working with Java since 1998 and still love it. I know people get a big kick out of writing code with no exception handlers and no curly braces, and programming is a creative/artistic process so you have to do what feels good... but none of that stuff ever bothered me.
I like being a pedantic programmer.
[0] http://www.javacodegeeks.com/2011/07/java-7-try-with-resourc...
[1] http://artisans-serverintellect-com.si-eioswww6.com/default....
[2] http://openjdk.java.net/projects/jdk7/features/#f250
[3] http://openjdk.java.net/projects/jdk7/features/#fa537814
[4] http://openjdk.java.net/projects/jdk7/features/#f639
[5] http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/0...
[6] http://mail.openjdk.java.net/pipermail/coin-dev/2009-Februar...