Closed Classes
I'm not sure if there's a term for this, but it's the opposite of what Ruby calls Open Classes. Open Classes allow you to define or redefine behavior on any class at any time. Java does not give me this ability. Let's look at a simple example, say I want to define a method that checks to see if a string is null or empty. In a language with Open Classes you can add behavior directly to the String class, so you could check to see if a string is null or empty by asking the string itself.
string.empty?
In an Object Oriented language, where objects are supposed to have appropriate behavior, I like having the ability to add the correct behavior to the correct class.
In Java, I'm stuck doing something very different. I could import some class defined in some library that has way more than I actually need, or, more likely, I'll just define my own StringUtils class and create a static method. In Java 6 I can static import this method, which makes my code procedural, joy.
If you are in the .net camp, don't laugh too loud. Your extension methods are flawed. Until you can override existing behavior, you're only halfway to the solution.
Lack of Closures, Blocks, Anonymous Methods
Whenever I manipulate a list of items I find Java severely lacking. In Clojure I can double each element in an array by simply calling the map method with an anonymous function and a list.
(map #(* % 2) [1 2 3])
In Java I'm stuck with iterating over the array, and adding the results to a temporary collection that is appended to with each iteration. I find that ugly, but it hardly compares to the absolute disgust I have for classes like Comparable and Runnable. An anonymous class instance that has one method is an obvious sign that the language is severely lacking in the area of closures, blocks, or anonymous methods.
Army of NNPPs
Java is currently the "one language to rule them all". This brings about several problems, one of which is the number of terrible programmers writing Java code. I'm lucky enough to work for a company that wants to "build the best software development teams in the world", so I don't work with a single person that writes code I find ugly. Unfortunately, that doesn't save me from the Java NNPP zombie army. Java NNPPs flood the forums and mailing lists with elementary questions and incorrect answers. The amount of signal to noise is so low that I find myself unsubscribing from every public mailing list, and avoiding all Java related forums. It's a shame that I generally have to stick to private mailing lists just to ensure I receive relevant answers.
Literal Arrays & Hashes
Arrays and Hashes are used so frequently, there's really no excuse for not having a literal syntax. In production code this is somewhat painful, but it really shows up in tests. Java does have a few solutions, two of them can be found in the following example.
1, 2, 3, 4} {
While these do offer "options" they both end up causing problems. The asList method works for about 75% of situations, but leaves me disappointed at least 25% of the time. Far too often there seems to be a method that doesn't like the return value of asList; therefore, I end up doing something significantly uglier to build a "correct" collection. The second example, the traditional Java array also works, but it's ugly to create and often to limited to work effectively with.
Command Line Execution for Snippets of Code
Sometimes you need to do something quick and simple. A command line interface (Ruby's IRB, Clojure's REPL) makes you more effective by seconds or minutes, millions of times a year. That wasted time adds up.
Java (the programming language) is so amazingly verbose (I'm talking about Java, the programming language)
Java forces me to repeat things all the time.
{
// handle new order
}
} {
In 2 lines of code I managed to type "NewOrder" 4 times. Even with a fancy IDE this gets very tedious. When writing Java code I don't actually write anything, I just keep hitting [Ctrl + space] and [Alt + Enter] all day long. When I'm writing code this tends to not be such a problem. I use IntelliJ for all my Java programming and I'm comfortable admitting that I can write Java code as fast as I was writing Ruby code.
The problem is, I don't spend all my time writing code. I spend a fair amount of my time reading code, code someone else on my team wrote, or code I wrote a few months ago. While I can write Java (or at least [Ctrl + Space] Java) as fast as I can write Ruby, it takes me at least 3 times as long to digest the responsibilities of a class written in Java as compared to Ruby.
These days I spend far more time trying to digest a class that takes 4 other classes as dependencies and each of those classes combine with the original class to solve one problem. Unfortunately it takes so much code to get something done that the simple behavior had to be split among 5 classes. To make matters worse everything has to be injected via the constructor because it's the only reasonable way to write testable software. So I end up reading pages of code to understand how each piece collaborates to do one simple task, awesome.
Extensive Tool Support Raises the Barrier of Entry for Tool Builders
I find the Java testing frameworks, much like Java itself, to be a generation behind. There have been steps forward elsewhere and the Java testing frameworks haven't yet caught up. I'm not one for complaining without providing a solution, so I started toying with building a testing framework. Does it integrate with IntelliJ? Of course not. Does it integrate with Eclipse? Absolutely not. Would anyone use it without integration? Emphatic No.
So now it's not good enough to create a good library, now I have to learn about IDEs also. Or (in my case anyway), drop the idea for more interesting pursuits, like finding the language I can replace Java with.
Conclusion
Java's not all bad. In fact, it might be the best tool for the work I'm doing these days. It's definitely tops in the areas that I need to be successful overall. But, I really do miss the things listed here, and all the other things that I've forgotten to write about but consistently swear about at work.
Happy New Year! Here's to a year where I find a suitable replacement for Java.
If you are in the .net camp, don't laugh too loud. Your extension methods are flawed. Until you can override existing behavior, you're only halfway to the solution.
ReplyDeleteMay I know how the extension methods in .Net are flawed?
Huh. You can't call string.isEmpty()? Something's wrong, dude.
ReplyDeleteBut why would one use Java in this day and age? This is an honest question - integration with legacy code can be done via JVM language (e.g. jruby), and speed is not an issue (you can code speed-critical parts in anything you want and link via JVM)...
ReplyDeleteSo, why is your company choosing to lower productivity of programmers by forcing them into Java?
P.S. Everybody: this is not a flame. If you think productivity is not lowered by Java, fine by me, there is no need to discuss it.
"May I know how the extension methods in .Net are flawed?"
ReplyDeleteWell extension methods are basically static methods under the covers, the compiler simply allows you to call the method as if it was define in the class. you cant override a method using extension methods, An extension method wont be called if it has the same signature as an existing class member. since its a static method an extension method doesnt have a access to the classes protected memebers
Greetings,
ReplyDeleteI enjoy Java, and develop in it a lot, but I agree that the amount of sheer busywork you have to do, just to write a decent program is often a pain.
Reading even average quality Java code can be eyeball-bleeding painful, and can impose a mental fog that makes it hard to isolate the actual behavior in all the verbosity and abstraction.
As for the .NET extension methods, the flaw being referred to afaict is that there is a bias favoring the original methods. They should at least allow the original methods to be shadowed by extensions, and optionally chained to in some 'super.foo' like way. Not a .NET programmer & don't want to be, though, so I'm sure Jay can expound more...
-- Morgan
Greetings,
ReplyDelete@izidor: There is no UI library comparable to Swing in Ruby, and JRuby/Swing is an ugly beast.
For me, for cross-platform desktop app development, Java is still nice.
I tried adding JRuby to a desktop app, so I could transition it over to 'UI in Java, Logic in Ruby', but it added 5-6MB in size, and several seconds more startup time, which my users couldn't swallow.
-- Morgan
You, my friend, are no Zed Shaw. Which is, you know, great, cause the world doesn't need another Zed. Thanks for elegantly summarizing so many reasons why it would suck to go back to working with Java (the language).
ReplyDeleteOh, and Feliz CumpleaƱo, bitches! ;)
It's nice to hear you're pragmatic attitude toward Java. It's getting long in the tooth, but I'm still able work productively in it only thanks to great tools (ctlr + space).
ReplyDeleteThat said, I've been playing with Scala at home over the last couple weeks while simultaneously building a somewhat complex library in Java at work. Now every time I declare a variable or write "for" in Java, a little bit (more) of me dies.
Hopefully over the next year or so Scala, JRuby, et al will make some serious headway so we can escape Java the language while reaping the rewards of Java the platform and all the code that already exists for it.
And, if I had a nickle for every time I've written effing StringUtils.join() ...
Nice post, you inspire me to indulge the whiner in me by writing my own 'Why X sucks', and I think I ought to claw back an iota of objectivity by writing it about my favourite language, Python.
ReplyDeleteYou could always try BeanShell for something similar to IRB.
ReplyDeleteAnd a Happy New Year to all!
I second the beanshell reference. Also I am curious :
ReplyDelete"To make matters worse everything has to be injected via the constructor because it's the only reasonable way to write testable software."
could you possibly elaborate about this ? what is the problem you have with setter/getter injection while testing ?
@Jean, the comment about injecting isn't really about constructor or setter injection, it's that, in Java, you need a form of injection to make the code testable. In contrast, you really don't have to worry about injection in a language with features similar to Ruby, because you can dynamically stub methods or redefine behavior of a dependency easily.
ReplyDeleteDateTimes are a really good example. In Java you often pass a DateTime around when you want to get the current time, because in your tests you can't freeze a moment in time. In Ruby, you can redefine the DateTime.now method and freeze time for an individual test.
Thanks for your comment.
Cheers, Jay
I recommend using Groovy if only for the groovy console. They have a nice shell (groovysh) and a little gui app (groovy console). You can write java code in it in addition to groovy code.
ReplyDeleteI spent a year in Ruby land and had to go back to Java land so I know the pain. I miss all you mentioned as well as stuff like reg ex literals, multiple return values, gems, and rake. rake is *SO* much better than anything in the java build world.
Jay, I honestly feel as if you phoned this post in, normally your posts are much more informative and thoughtful!
ReplyDeleteThere are a ton of reasons why programming in Java is no fun at all. I would have expected some of the amazing things you can do with testing in Ruby to be something highlighted, like redefining methods on an instance. Also, the lack of ability to mix things in and not to mention string interpolation and duck typing.
You can actually redefine methods methods on an instance in Java, by overriding the method at construction time. It's not as nice as what Ruby has, but it is possible.
ReplyDeleteI do miss string interpolation, but it's not something I do very often, so I guess that hasn't been a big pain point either.
Duck typing, yeah, I did miss that one. To be honest, I haven't experienced a lot of pain in this area either, but only because Mockito allows you to mock concrete classes. Still it is annoying enough that I probably should have included it. Next time I feel like complaining about Java, I'll be sure to add that as well.
Sorry the post disappointed you. I expected to upset the Java crowd, I didn't expect to get it from the Ruby crowd as well. ;)
Thanks for the comment.
Cheers, Jay
Some good points - Java collections aren't as easy to use as in Ruby/Python/Groovy etc. But some points that are just subjective (nothing wrong with this in a blog of course :-). 1) Closed classes are not a problem for many large corporate IT shops, which is where languages like Java aim to play. No *way* my company would allow java.blah (or C#'s System.Blah classes) to be overridden. It might be fine for you and your team, but not good for the (possibly NNPP) programmers who will be looking after your system years from now when you have moved on. Similarly, this also mitigates Java's and C#'s wordiness as well. 2) As for the army of NNPP programmers - meh, this happens with any popular language that the universities are churning out green programmers for. 3) high barrier of entry for tool builders - true, if you want people to use your tool, you have to make it easy for them or make something game-changing that rocks. The former is a PITA (like documentation) that hackers find boring - so if you can't do that, do the latter and a community will form and they'll help with the boring. If you can't/won't do either, then it's no great loss really. There is a *huge* amount of *excellent* Java open source - more than any other platform - so competition is fierce. You've got to be hungry to play.
ReplyDeleteInteresting article though I have some serious issues with it.
ReplyDeleteOpen classes are powerful but get really scary really quickly when everyone just starts monkey patching everything.
I do agree Java needs some prettying up around closures, but everyone agrees at this point, its just a matter of time.
NNPP's are everywhere in any language that gets at all popular. If you only stick to clojure you might be able to get away from them but good luck finding work.
I would like some literals, no argument there.
Most IDEs let you do execution of snippets of code, but really this is a static vs dynamic issue not a Java specific issue.
Finally, a large amount of the complexity actually comes from a lack of closures like the example given. Again, just a mater of time.
"Closed classes"
ReplyDeleteThe fact that in Java everything must be there at compile time is in my opinion one of its key strength. Yes, redefining a method at runtime can be nice at some point, but the strictness of Java is what enables the fabolous tools around it.
Lack of Closures
That is very true. Having spent some time writing code with closures makes you take a second look at your Java code. It is insane how imperative it is to apply a function on every element of a map. The "Closures Debate" in Java has been around for quite some time and there are working proposals for adding Closures to Java (BGGA, CICE), but it wont be in time for Java 7. I hate designing a new "Single-Method-Interface" every time I want to pass a snippet of code to another method. It is too much overhead.
The CLI
I recommend to install Groovy. It has a nice CLI and you can easily work with your existing java classes and monkeypatch some methods and so on.
Testing Frameworks
Have you tried Mockito and EasyMock?
I am on vacation so I would like to answer to your post.
ReplyDeleteFrankly I am 90% not of your opinion.
Extend String - a nightmare to me.
Extends is the most abused and catastrophic feature of Java.
I dont worry about language features in Java at all really, because this is never the problem. But bad design is.
Typing code in Eclipse only takes a fraction of my time.
Create a new Class type: new MyClass(aField) - thats it.(optional create the fields you might need and generate setter/getter/constructor - TIME: one minute to a full featured Class)
Run a snippet type : main -and put your code into the generated main method.
Anonymous inner Classes?
TAkes a second to create one: new IWhatEver(strg space)choose - (left{ hit enter - hit down; - hit up up - (hit strg f1) add missing methods- finnished.
If you've not taken a look, you might find the Fan language more to your taste - http://fandev.org. It takes Java and applies most of the fixes everyone wants including those on your list (except open clases, which I'd say are a bad idea). Fan is still young and not yet complete, but it shows great potential.
ReplyDeleteMaybe you covered this in another post, but why is JRuby not an option for you guys? Seems like it would be viable to write most code in Ruby and drop into Java for perf critical sections. Surely the language change to Ruby wouldn't be a problem for the crack team it sounds like you guys have there. Just curious.
ReplyDeleteJRuby is neither mature enough or fast enough for what we do on my team.
ReplyDeleteAs far as maturity, we use it for some testing and have run into problems. Nothing I can publicly discuss, unfortunately.
Speed wise, every millisecond counts in the app I'm currently working with. JRuby imposes a cost that isn't realistic for us at this point.
That said, there may be other languages that provide the maturity and speed we need. That's a question I'm going to try to answer in the near term.
Cheers, Jay
Why not Clojure?
ReplyDelete@Paul, I've been looking into it, thus my examples in Clojure. I've been happy with the language so far, but haven't had a chance to try integrating it with my production code.
ReplyDeleteReally, the only thing I'm waiting on is 1.0
Cheers, Jay
There are two arguments here that associate groovy success to its lack of maturity:
ReplyDelete* The abundance of NNPP: where do you expect them to move once groovy gains traction?
* About Open Classes: I suffered this using javascript not so long ago: library A extends Date in a way not compatible with library B. Java included the SecurityManager (which is currently not used) to protect against this. Malicious purposes are also welcome.
There are lots of arguments in the Groovy vs Java debate that smell funny to me. Others are valid, though.
I have to agree with the guy that does not agree with this article. First of all, as he said, most of my time is used up by using the IDE features of NetBeans or Eclipse.. I can quickly use a few keyboard shortcuts that do most of the code work for me. I don't understand those that complain of the redundant code in Java. Let's go back about 10 years with early Java, crappy IDEs if any, and how about before that.. with C, Pascal, etc... imagine the amount of time we spent then, and yet back then we were happy to be writing code. Now, with in my opinion the most robust language and platform out there, the Ruby convert programmers complain about things that take 1/100th the time as they did just a few years ago. It blows my mind. Is it really that hard to copy/paste.. and code completion, ctrl+space or ctrl+enter to complete typing, etc.. it's incredibly easy and very fast to write java code these days. A few years ago it was said on a good "6 hour" work day (6 hours if you include lunches/interuptions, meetings, looking things up, etc), a good programmer could do about 300 lines of code.... of good quality code, not just stubs/templates. I honestly think I can do about 3000 lines of good code in a day if not more when I am focussed. Most of this I attribute to the speed and features of the IDE, helps that I type fast too.
ReplyDeleteI am really blown away at how someone goes to Ruby from Java and then cries about going back to Java. Yet, most ruby developers I know end up running their ruby in JRuby because Ruby/Rails is just too slow... still.. even after a few years now of so many supposedly switching to Ruby because Java is just so horrible and Ruby is so dang easy. And yet, the few times I've played with Ruby, I look at the code and am horrified. After years of Basic, Pascal, C/C++ and now Java, at least these languages have readable code. Ruby has what I like to think of as scripting elements to its language. It reminds me of Perl in so many ways, and neither are easy to read languages, nor are they nearly as good as Java for just about everything. Sure.. on a whim, I'd use perl or bash script or something for quick scripts. But I get so much more flexibility and massive libraries behind using Java for anything that requires a little bit more than simple scripts offer. And how hard is it to run.. java -jar somefile.jar -options. Wow. It's no harder than running any ruby code, or perl script. Java these days is pretty much installed on every computer, and with 1.6 startup times, it's no slower in my experience on slower older machines or newer ones in starting up than any other native app or script. There are some cases where it may be slightly slower.. large Swing apps that build up a heavy UI before showing up, for example.. but that's a matter of the app design... I've seen quite complex Swing apps start up in under a second as well.
The sad thing is, most of the readers of this post that would even comment are ruby fanboys or java haters (for one reason or another). By haters I don't mean you hate the language (or platform) so much as I mean that most of us that love Java the language and live and breathe it don't waste time commenting on posts like this. So you see 5, 10, 20+ comments on various posts like these and most of them are the very tiny portion of ruby/pick your non-java language fan who make a comment to plug there favorite language and make Java look as if it's no longer being used and no jobs exist for it. Truth is, Java is massive, all over the place. Java is the most robust/capable UI kit there is, period. The server side is all about Java, despite the few that like to claim .NET is gaining ground/overtaking java, or that Ruby is the new Java and JAva is dying/going away. None of it is close to the truth. If you look up jobs right now, even in our overly sad economy, Java in most "tech" areas hands down beats every other offering combined. Java continues to improve, in features and performance, so it's not going away anytime soon.
Yah, I am passionate about Java, but more so I am really tired of seeing all the random posts that say Java is not a hot job, java is dying, java is going away, Ruby/Groovy/.Net/Python are better/more jobs/etc. It's merely a bunch of crap that some random person posts to try to get attention.. just one person here and there with a few comments added in for good will, to hopefully boost their favorite language above Java, the current King of choice for just about every type of application out there.
Sorry for the "anger", it's a new year, world peace should ensue.
@anonymous, did you even read the blog post? I, pretty clearly, state that I can write Java as fast as I used to write Ruby.
ReplyDeleteImagine how you'd feel if you went back to writing Pascal these days. That's how I feel about doing Java.
The article isn't about Java vs. Ruby, it's about the things I dislike about Java. Some things come from my experiences with Ruby, others from other languages (such as Clojure). You can love Java and still admit it would be a better language if it weren't so verbose and strict.
I never said Java is dying, or really anything other than the fact that I dislike not having the missing features and I'd love to find a language that would provide me the low-latency and integration story that Java does.
Your response is so irrelevant it sounds like a knee-jerk reaction, to me anyway. Maybe you should tone down the Java love to a point where you can have a logical conversation about it...
Cheers, Jay
@anonymous I find it hard to believe that you can write 3000 lines of code a day in any language. I've worked with some very smart people, and no one has been able to produce anywhere near that amount of code unless they are churning out pure garbage.
ReplyDeleteI worked for two years on a webapp with 4 people and our LOC count was under 60K for a large and very complex application. That includes specs and application code.
Perhaps if you slowed down a bit and thought about your problem you wouldn't need to write that much code.
try IBM Portlet Factory for those to help speed up things for those who find writing java code from scratch a problem.
ReplyDelete.... "doesn't save me from the Java NNPP zombie army. Java NNPPs flood the forums and mailing lists with elementary questions and incorrect answers."
ReplyDeleteThis statement makes you sound pretentious, and probably is a catalyst for knee-jerk reactions.
"Elementary questions and incorrect answers" is subjective.
It really isn't subjective...because there are standard things that every developer should know for a specific language. And the statement about NNNPs flooding forums is quite correct, because they are the ones frequently repeating the same question over and over again.
ReplyDelete@isaiah: "since its a static method an extension method doesnt have a access to the classes protected memebers"
ReplyDeleteNo, static (shared in vb) methods DO have the ability to access private members. You just need to pass in the object that is the same type as the class of the shared method you are calling, and that method will be able to do anything to that object that the object itself could do.
I use this sometimes when I use classes for things, and some NNPPs (bosses, lol) don't understand how classes work, especially if they are not built into the .NET framework (I got yelled at for using objects in an OOP language!). So I created static methods for him to use which employ creating an object for the class, then performing all the necessary functions.
Most of the times I dislike Java because Java does not support multiple line string literals. It makes writing SQL in Java very annoying
ReplyDeleteI've worked with people who can write 3000 lines a day. I've seen it done. On the other hand, my job was refactoring their sh*t stream into maintainable code, which resulted in shrinking the code base by at least a factor of 10.
ReplyDeleteIf I were a manager who had someone writing 3000 lines of code a day, I'd fire them on the spot.
Hi, here's a possible solution to your Arrays/Hashes problem that I use in my app. It's not perfect (sometimes you have to cast the first field to a base type) but it's MUCH more convenient than the two things you're resorting to IMO. http://pastebin.com/f36a977d9
ReplyDeletePlus, the methods are static so when you use this you can shorten it to ... = newList("a", "b", "c");
Here's another hack you can use. But, I would never use this in production and avoid it in test's: http://pastebin.com/f49a841a3