In the Java booth, Jim Holmlund gave me an overview of upcoming
features in Java. (Luckily for me, he had a copy of the speaker's
slides. So it made up for the session I missed in the morning.)
Some of what's coming is pretty cool. Some is a bit dissapointing,
compared to what I was hoping for. Here's my notes:
Java 7
Java 7 will get a variety of small language enhancements that are
part of the COIN
project:
Strings in Switch Statements A long overdue addition, the switch statement will find uses outside of low-level tokenizers that switch
on character bytes and integers. It will be possible to compare
strings, making a "dispatch" utility that will have many uses.
Underscores in constants When you're putting 1000000 miliseconds into a constant, you'll
be able to make it more readable by writing
it as 1_000_000. The compiler will then strip out the underscores
to produce the actual constant.
Multi-catch Instead of being limited to a single exception per catch clause, you'll be able to catch multiple exceptions
in one clause, and handle them each in the same way.
Autoclose interface One of Ruby's goodnesses here. If you implement the autoclose
interface, you can put input and output streams in a single try block
and, when the block ends, all of the streams are closed. It's an important
feature that saves you the headache of making sure that you close everything
when an exception disrupts the flow of processing. It will also eliminate
memory leaks that can accumulate when programs are terminated abnormally,
either externally or internally. That capability, in turn, means that
a VM will be able to stay up longer before memory leaks force it to its
knees.
Default methods for interfaces
When defining an interface, it will be possible to specify a default implementation
for a method signature. That feature helps in two ways. First, it means that
implementation code which is typically written the same way can be provided
in one DRY location. Second, it means that an interface designer can provide
null implementations for features to be added at a later date. The idea is
that older code won't break when new features are added to implementation
objects.
For example, let's say you publish a tree-processing interface.
Any object that implements that interface can be given to your summation
method, which will add up all the values in that tree. (A directory tree,
for example, with a count of files in each directory.) I use that summation
processor, and you do too. One day, you know you'll want to add up the file
sizes, as well. But you don't have time to implement
it right now. If you require tree interface to have a size() method, you
force me to implement it, even though it's never used. But if you don't,
you can't add it later without breaking my implementation. You naturally
don't want to do that, so you define a default size() method. Then, when
you get around to it, you define a diskSpace() method that takes a Tree
object, and you define a size() method in your DirectoryTree implementation.
Everything works for you. As for me, I never implement size(), but
I don't care: I never use that newfangled diskSpace() method
anyway, so the default implementation of t size() is good enough
for me.
Type "Inferencing"
This is one that sounded good on paper, until I found it what it actually meant.
I was hoping for something that
would put an end to "viral generics". You know, when a library
returns a generic, and you call that API, now you have to put the
generics on your variable to make the warning go away--and when you return
it, everything that calls you has to have generics added. (Old languages
used to have 4 pages of warnings, making it hard to spot the errors.
To this day, I dislike warnings.)
So my expectation for "type inferencing" was that it would work sort
of like Ruby or Scala. If f(x) returns an ArrayList of String,
then there would be no need to code ArrayList<String> list = f(x).
Instead, you would just code
list = f(x), like you used to, and the compiler would
figure it out..
No such luck. Instead of inferencing from right to left, as
I expected, it works the other way around.
Instead of specifying
this: List<List<String>> list = new ArrayList<List<String>>();
You'll be able to specify this: List<List<String>> list =
new ArrayList<>();
Granted, it's an improvement. But it's a pretty small improvement. And it's
not even really type inferencing. Instead, it's type deduction: If
you tell the compiler what the type is on the left side of the
assignment, it can figure out what the type has to be on the right side, a few
characters later. I should hope so.
Pardon my disappointment, but I was looking for a lot more.
Java 8(ish)
VM Support for Dynamic Languages:
These features will make it
possible for truly dynamic languages to be implemented without
compromise. (Fully dynamic type safety for languages like JRuby
comes to mind as one of the features that will probably be implemented.)
LambdaJ:
This features makes functions into first-class objects
so that, for example, an anonymous function can be passed as an argument
to a method, using syntax like this:
#{..function definition here...}
That's an important step towards functional programming
capabilities, of course. But it's only one of several steps that
are needed, and it's going to be a year or two before Java 8 is available.
(For more on that subject, see the next report.)
> Default methods for interfaces > > When defining an interface, it will be possible to > specify a default implementation for a method signature.
I'm confused by this. How are these new interfaces different than abstract classes, then? The only difference that I can see is that you can implement multiple interfaces, but only extend a single class. Given that, why would anyone continue to use abstract classes then?
Also, how is multiple inheritance resolved when multiple interfaces have different default implementations of the same method signature? Is multiple inheritance no longer considered evil by the Java community?
Just assuming based on the description: 1. Interfaces cannot have constructors (abstract classes can). 2. Interfaces inheritance is multiple inheritance (class inheritance is singular).
@all
Does this make Java interfaces just like Scala's Traits?
When a class extends two interfaces. Who both have an extends (default) method with the same signature and the class does not override this the code will fail with a linkage exception.
See section 3.1 Resolving Ambiguity of the proposal Defender Methods. "http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf"
Ah. It looks like default methods will likely be used to provide a Java equivalent of mixins.
BTW, will there be a way for a class to explicitly invoke a default method that was overridden? That is, will there be an interface equivalent of super.foo()?
> I'm confused by this. How are these new interfaces > different than abstract classes, then? The only difference > that I can see is that you can implement multiple > interfaces, but only extend a single class. Given that, > why would anyone continue to use abstract classes then?
Abstract classes can hold state (i.e. have instance variables).
> now you have to put the generics on your variable to make the warning go away
That's a funny way to put it. I'd rather say that you have to specify the (correct) type for your variable. I agree, though, that this should be inferred for local variables.
>Type "Inferencing" > This is one that sounded good on paper, until I >found it what it actually meant. I was hoping for >something that would put an end to "viral generics". You >know, when a library returns a generic, and you call that >API, now you have to put the generics on your variable to >make the warning go away
Interesting that you dislike this. I find one of the huge advantages of generics is that people have to write down that the list is a List<Foo>, so, when I look at the code written 8 months ago by somebody who has left the company, I know what's in the list.
Before generics, I spent a lot of time tracing through code, or inserting a breakpoint and actually inspecting, to see what was in the Collection, because the javadocs were, as is true for many comments, missing or wrong.
> Instead, you would just code list = f(x), like you >used to, and the compiler would figure it out..
o.k., that could be nice, assuming that the local variable list is only used within a few lines of here. But, what if a few months later somebody changes the code and moves or uses list a page down. Then a few months later you are staring at the code wondering what's in list?
> Instead of specifying this: List<List<String>> list = >new ArrayList<List<String>>(); > You'll be able to specify this: List<List<String>> >list = new ArrayList<>();
Here I'm not sure what you are complaining about. You can't very well go
List list = new ArrayList();
and expect the compiler to figure anything out. :-)
This would appear to imply that the default implementations in the new interface proposals would not be able to refer to state variables. Is that the case?
> This would appear to imply that the default > implementations in the new interface proposals would not > be able to refer to state variables. Is that the case?
That is indeed the case. The target use case is for adding things like a foreach method to Iterable once closures are added. It can be implemented by simply referencing the existing iterator() method, and individual implementations of Iterable can choose to override the default implementation with something more efficient if they wish.
Morgan Conrad wrote: > I find that one of the huge advantages of generics is . that people have to write down > that the list is a List<Foo>, so, when I look at the code > written 8 months ago by somebody who has left the company, > I know what's in the list. > Granted, that is an advantage that tends towards readability. At the same time, the explosion of syntactic tends towards obfuscation. So to my mind, there is a tradeoff.
Given static typing, a type-inferencing IDE should be able to come to the rescue and provide the best of both worlds. NetBeans does a pretty decent job of that for JRuby, thanks to Tor Norbye. Maybe I just got spoiled.
No, but every other language with type inference expects a compiler smart enough for:
var list = new ArrayList<Integer>();
The Java solution is simply backwards. Instead of inferring the type of the variable, it infers the type of object that then gets assigned to the variable.
Not to make a big deal of it, but, from a "purist" point of view, one could argue that the Java way is superior. Why? Because "they say" that you should code to the interface, not the implementation. Your mental model should be of the interface, not the impl. Since the left side is the interface, the details (the type) should be there. The right side is the uninteresting implementation.
Pragmatically, I could care less, I'm just happy to have half as much typing.
Flat View: This topic has 47 replies
on 4 pages
[
1234
|
»
]