Hacker News new | comments | show | ask | jobs | submit login
An Opinionated Guide to Modern Java Development, Part 1 (paralleluniverse.co)
553 points by pron 1266 days ago | hide | past | web | 396 comments | favorite



I like the changes in Java 8, but I'm concerned about Java fragmentation between Oracle/OpenJDK and Android. It seems Android is stuck on Java 1.6 (since Dalvik is not "true Java" and is more like a VM that happens to implement a language very similar to Java 1.6). There's now a huge gap between 1.6 and 1.8. It's not just syntax like lambda and default methods. It's also the supporting API changes in collections (streams) and others. Dalvik was based on Apache Harmony which is a dead project and will never get the Java 8 API changes implemented. Does anyone know if Google is going to do something about Java 8 and Android?


Dalvik is being slowly replaced by ART (Android RunTime). Also, you can pretty easily hack Java 7 or even Java 8 into Android to use lambdas. Official, default support is coming soon.

http://tools.android.com/tech-docs/new-build-system/user-gui...

http://zserge.com/blog/android-lambda.html


Except those lambdas are not as efficient as the standard compliants VMs, as they make use of invokedynamic to generate better code, even inline calls for small lambdas.


Are you sure about that? I've looked at the way invokedynamic generates lambdas, and it's just generating anonymous classes at runtime using ASM. Inlining is from the JIT and applies to anonymous classes as well. I'm pretty sure you can get the exact same results without invokedynamic, you just have a lot more .class files to distribute.


I think you got it right. According to Grzegorz Kossakowski's comment (which is more accurate than the misleading article) : http://www.takipiblog.com/2014/01/16/compiling-lambda-expres... , Java 8's lambda's aren't particularly efficient. They do create an anonymous class instance at runtime, as you say. Scala closures are implemented in a similar way, without invokedynamic, and as he says, and currently there is no performance win from invokedynamic's use in Java 8 vs the Scala impl. But it does hold promise of future optimizations, as he says:

"However, the key thing about invokedynamic is that it's essentially a JVM-level macro that defers lambda translation strategy to LambdaMetaFactory which is a library class. If Java 9 or 10 gets more direct (and performant) support for lambdas that won't require classes and object allocations then it can swap implementation of LambdaMetaFactory and all _existing_ code written for Java 8 will get performance boost. That is the brilliance of using invokedynamic in context of translating lambdas. We'll have to wait for future versions of Java to experience those benefits, though."


I don't think that person understands how it works at all.


He knows what he is talking about & his description matches the explanation by Brian Goetz.

So unless I'm missing something, please be specific.


Well, for one, Lambdas are desugared into methods, not anonymous classes. Early on they used anonymous classes because it was convenient but that wasn't the final translation strategy.

http://cr.openjdk.java.net/~briangoetz/lambda/lambda-transla...


My impression from the openjdk code is that each lambda generates:

1. A method in its parent class. 2. An invokedynamic instruction at the call site.

The invokedynamic instruction calls LambdaMetafactory, which compiles an anonymous class at runtime that calls method #1. So the only benefit of using invokedynamic is fewer class files, by deferring generating them until runtime.


Non-capturing lambdas also don't instantiate a new object at each call site. But this is also doable without invokedynamic.


Yes, and these methods create an anonymous class at runtime. What's so hard to understand about this?


It was a misunderstanding on my part about where they were claiming the anonymous class was generated. Early versions of Lambda were nothing more than sugar on top of anonymous inner classes and the claim above sounded very similar to that. However, I see that inside the LambdaMetaFactory anonymous classes are generated based on the call site. Probably the biggest difference is that Java 8 can avoid an object allocation when the lambda doesn't capture. Not sure if Scala supports this but I'm sure that it could do it.


Since I cannot edit my reply.

Have you checked this talk at Java ONE?

http://parleys.com/play/5251c164e4b0a43ac1212459/about

Some older slides also available

http://www.slideshare.net/jaxlondon2012/lambda-a-peek-under-...


I am basing my comment on the Java One talk about Java 8 lambdas implementation on the Oracle JVM.

I assume other certified JVMs would follow similar design approaches.


But it allows people to move forward using the syntax itself.

The implementation can be optimised at any point.


Which might be fixable with ART as it's an on-device ahead-of-time compiler (I think it optimizes too? can't find references...). I have no idea if it actually does work for this in practice or not, though.


True, but it won't help users with KitKat and lower devices. We all know that they won't see any vendor updates.


Well sure. But people don't update their Java installs either, neither do all businesses. They're likely not going to be able to take advantage of v8 stuff. And can dumbphones on a Java platform (Symbian? Nokia? Others?) run the new Java flashiness? Every platform has problems like this.


>> Official, default support is coming soon.

Default support of ART or Java 8?

If Java 8, how do you know this? Citation needed ;)


Java 8.

Arguing whether Java 8 will be completely supported or not ignores the nature of the Android API. Android doesn't even support 100% of Java 6 because it is not a desktop JDK and does not intend to replicate everything.

However, the Android team has actively been adding default support of Java 7 features piece by piece in recent months. They intend to handle Java 8 in the same manner. It's not clear which features will be supported in what version of Android, but lambdas are clearly a priority and can already be used today by early adopters using retrolambda.

http://stackoverflow.com/a/22303654/1412973


There is a good reason that Sun didn't want this to happen and tried to stop it in court — successful against Microsoft, failed against Google. If I remember right, most everyone on here was rooting for Google to win and continue to fragment the language.


I supported Google because the ends don't justify means. People should have the right to re-implement APIs, even if we sometimes wished they didn't.


Well put. Just because it wasn't a good idea doesn't mean it should be illegal.


I have since repent myself.

Google did indeed managed to pull a Microsoft and now we have a forked Java implementation getting steady behind the standard Java implementations.

Even J2ME is more compatible with its big brother than Android.

KitKat has now partial support for Java 7, with libraries still missing some pieces. Dalvik and ART still don't support invokedynamic bytecode.

And since almost no one has KitKat, one cannot use try-with-resources anyway.


I wrote a lot of J2ME stuff a few years ago and you're spot on. I spent two weeks doing Java 8 bits with NetBeans which was really nice and spent the last two evenings writing my first Android app and what a complete mess it is. Plus the Android tooling is horrible to get working reliably - most problems being solved by "restart eclipse".

Late edit: perhaps Oracle should make a phone ;)


> Plus the Android tooling is horrible to get working reliably - most problems being solved by "restart eclipse"

Try Intellij IDEA / Android Studio. I find them quite reliable.


Intellij IDEA, yes.

Android Studio seems to still have performance issues with Gradle on Windows, specially when indexing stuff.


Agreed. I prefer IntelliJ IDEA Community Edition to Android Studio because I like using the same IDE for Android and Java development.


> Late edit: perhaps Oracle should make a phone ;)

They did an open spec tablet with a raspberry pi tough.

https://wiki.openjdk.java.net/display/OpenJFX/DukePad


Chuck a GSM module in it and done :)


I also did some J2ME stuff back in 2003, most with Sharp and Nokia devices.

I read somewhere that some in the Android team are C converts doing their first Java gig.

Have you seen how broken are the generated Renderscript bindings? They don't have anything to do with Java conventions and feel completely out of place.


Haven't looked at render script yet. Still scratching head on the layout engine stuff and View infrastructure. It's fugly. I usually write C#+WPF and C++/Qt and HTML/Java EE and all of those are massively nicer to deal with.


If you are two days in and still getting around how Views and layout works I wouldn't call it a mess yet. You are still pretty early into it. Its not messy its just new to you.

From my experience once you get past the initial hump of learning their basic APIs and conventions its a very easy to work with platform. Maybe I am biased because I spend a lot of time with it. I also really like the tooling. How is it acting unstable for you?


> "restart eclipse"

Eclipse

/shudder


After this week, yep!


> Even J2ME is more compatible with its big brother than Android.

Are you serious?

J2ME is even more crippled than Android's Java (no reflection, no Swing, no AWT and stuck in Java 1.4).

J2ME has been dead for more than half a decade and we have Android to thank for that. Good riddance.


I'm not sure where you get your information about this, but J2ME 8 was released alongside Java 8:

http://www.oracle.com/technetwork/java/embedded/overview/jav...


No invokedynamic though :-) https://jcp.org/en/jsr/detail?id=360

Also missing:

    Reflection
    Serialization
    Lambda expressions (JSR 335)
    JNI and application native code
    User-defined class loaders
    Full annotations support (Runtime annotations)
    Thread groups and demon threads
    Full Math APIs (with BigDecimals)
    Concurrency utilities
    Full security APIs
    Full collection APIs (Sorted collection classes) 
Source: http://docs.oracle.com/javame/config/cldc/opt-pkgs/api/cldc/...


J2ME has been updated to Java 8 and outside the mobile world is used a lot in embedded industrial deployments.


Forked != out of date. Android code is still Java code. you just compile to Dalvik bytecode instead of jvm bytecode.

If you think that's wrong, fine but that lawsuit had nothing to do with bytecode.


The question is what Oracle would lose by licensing real Java to Google at reasonable conditions. Mobile non-Android Java is deader than dead.


> Mobile non-Android Java is deader than dead.

Lots of embedded devices make use of J2ME, e.g. cars, manufacturing, electricity monitoring...


How many of those will get Java 8 updates?


The billionaires at WhatsApp beg to differ. They got very very rich from "mobile non-Android Java".


Isn't their stack based on Erlang or am I missing something ?


You're missing the client side. It runs on J2ME-powered feature phones.


And on Android (and probably iPhones). Which version was first, J2ME or smartphone one?


Oracle was offering licensing for "real Java" at around $1 per device. This was too high for Google that wanted to make it entirely free. Kind of silly, since Android hardware manufacturers pay much more than that to Microsoft in patent licenses.


It's unlikely that the patent licensing situation would have been different with Java ME. It is entirely likely that it would not have been completely open source due to Sun (and ultimately Oracle) restrictions on Java ME.


Hmm, what you write makes no sense.... even if Google would use Oracle Java, we'd still be stuck with devices running Java 1.6 JVMs.

Having a different implementation doesn't change the limitations imposed by out of date VM running on a device.


Why would they run 1.6 JVMs? Why wouldn't they run the latest?


Android already supports most of Java 7 http://tools.android.com/tech-docs/new-build-system/user-gui...

I'm not aware of any plans to support Java 8 yet, but I haven't been looking.


They support Java 7 syntax, however they do not have the API improvements in Java 7. For example, Java 7 introduced a much improved File IO API in the java.nio.file package. It has very useful classes like Files (http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files...)

Android does not have any of this (http://developer.android.com/reference/packages.html) because the Apache Harmony project died before it could implement Java 7 API changes.

This is a much bigger issue for Java 8. Just supporting only Java 8 syntax changes greatly reduces the benefits of the new lambda and default methods. Much of the power of the changes, especially lambda, require the changes to the collections API.


No, Android does not have any of this because Apache Harmony was killed by the Java 7 API changes. Namely, the documentation was no longer open, and Oracle withheld the TCK, effectively killing Harmony by making it uncertifiable as a Java implementation.

Harmony didn't die per se - It was killed by Oracle. Google's rationale for engineering a Java-ish VM with Java APIs was only legal up until Java 6.


Guava works on it though, thank goodness!


If you target only KitKat and don't mind missing some of the Java 7 new APIs.


There's always been some fragmentation between Dalvik and "real" Java. A lot of libraries don't work out of the box on Android.


Not to mention debacle it creates on your system. Android requires/plays-well with JDK 6 and you probably want to be running the latest version of Java for security purposes. Maintaining multiple JDKs have been nothing but troubling for me.


Uhm... Android tools work just fine with the newsest stable JDK 7.


I hear not all libraries are supported. developer.android.com and almost all tutorials/courses recommend using JDK 6.


Especially since Google hasn't updated its Java language much lately. I think the solution for Google is to deprecate Java and start using Go. That would solve more than one problem for them.


Back when I was initially impressed by Go before the 1.0 release, I created a ticket for Go on Android, which is still open.

I doubt it will ever happen.


There are a bunch of rumors that Google will announce expanded GoLang support on Android at IO. What that means I'm not sure and I can't find the link for it now. It was a somewhat credible source but not one I'd bet the farm on or anything. I suspect if anything is announced it would be GoLang ndk support but we can dream and hope for more. A python to Davlik compiler would be a very interesting move also.


> A python to Davlik compiler would be a very interesting move also.

Dalvik is dead. It has been already fully replaced on the latest AOSP code drops. Plus SL4A was left to rotten.

As for Go, lets see. My ticket is now two years old.


> Especially since Google hasn't updated its Java language much lately

Yes it has. They recently added Java 7 language support.


I'm back to java after having an unsatisfying experience 2 years ago with Spring MVC, (this time i use the "play framework"), and it seems to confirm my intuition that the language itself is really just fine. The problem lies more in bloated frameworks and corporate culture where everything needs to be standardized, regulated, and the purpose of a mandatory non-free training session.

Add to that the fact that every single topic is covered by at least 3 or 4 libraries, and you get a more complete view of the situation.


I kind of like that things are standardized/regulated in the Java space. If you're using anything close to industry standard tools and methodologies I can come in and be an effective member of your team faster. I know it can sometimes be more exciting to build something in a way no one else has ever built it before, but it's usually a bad business decision to do so.

This is one of the reasons why I still lament javascript. It seems like everyone and their mother is using a different framework to accomplish essentially the same task. The flavor of the week last exactly that long: a week.


How's Play! compare to Spring? I'm working on a bloated Spring whale (1.5M LoC, 485 Spring XML config files) and wondering if something like Play! can do it better, or if complexity is simply a beast that will inevitably turn any project into a turgid mass.

I ask since friends at Google will laugh at a bar if you even say "Spring," but I'm curious what else can do it all (Guice/Gin?). Perhaps nothing can and the trick is to simply have small, cohesive projects linked by common REST (et al) API's and to merely skirt complexity entirely. However, for workflow and state management, you'll inevitably need some common integration point.


I did a side project in Play! some time ago. While it was generally OK to use, Java in Play is definitely a second class citizen compared to Scala. Most documentation (which btw is sorely lacking) concerns how to do stuff with Scala and you'll have to figure out how to do the same in Java yourself.

Even worse, breaking backwards compatibility between even minor releases seems to be standard for this framework. So once you've finally managed to find some piece of documentation from some random source on the net (as again, the official documentation is pretty much a joke) you'll find that it doesn't work at all because it was written with Play! 2.0 in mind which is different from 2.1 which is different from 2.2 and so on.

Once you figure it out, it's a pretty nice framework. It's a shame so little attention seems to be paid to exposing that in a better fashion.


> Java in Play is definitely a second class citizen compared to Scala

Much agreed. I started a side project with a quick deadline with Java in Play and switched to Scala (even though I had to learn Scala) just because they played better together.


Play 1.2 is not-quite-as-supported as Play 2.x, but it doesn't have features that mostly make sense for Scala (e.g., text-based templates, not Scala-DSL ones)


I can strongly recommend Dropwizard for the plan. It is much less stuffy/enterprisy and you can easily split big apps into smaller services. It is some glue code on top of Jersey run in embedded mode Jetty (thus very little ops work needed). Play Framework is also nice, but a bit too much opinionated! Meaning hard to make it do something in another way, which happens in real world big applications...


I've used Dropwizard but with my latest project I dropped it in favor of assembling libraries manually. There's nothing wrong with Dropwizard per se, it's biggest strength is that everything you need works out of the box, but it bundles some older versions of libraries (like jersey, jetty). I am now using latest Jersey, Jetty (embedded), Atmosphere, Ebean and RxJava with Kotlin. It wasn't that hard to setup everything manually and the benefit is that I can add anything I want. I work with Python and C# mostly and don't have that much experience with Java/JVM, but I really like this setup. I've also considered Play 2 with Java, but it didn't feel right to me and the documentation was out of date. Perhaps it's better with Scala, but I don't really want to learn an entire new language and ecosystem. Kotlin is similar to C# so for me it was a breeze to pick it up and I can transparently use any Java library with Kotlin by just importing it.


Jetty + Jersey that Dropwizard use is old (couple versions behind) AFAIK.


Jetty is up to date, but Jersey is old yes. But the new jersey is also a bit problematic, more stuffy and slow (from the benchmarks of others, I haven't done it myself). But the good thing is, there is a big and passionate contributor community around dropwizard (check their github/google groups) and this means if the new versions of libraries are worth updating, they get in pretty quickly.


Jetty is up to date, Jersey 2 is sitting in a PR right now.


Spring is a huge umbrella project that contains many parts, some good, some not so good. Guice or picocontainer work well, but you can achieve the same effect by using spring's Java configuration and avoiding silly things (AOP, shudder), and that way you can migrate existing spring XML piece by piece.

If you're writing an actual webapp (i.e. something that outputs html) then I highly recommend Wicket; it's the most beautiful framework I've ever used, in any language. If it's just REST APIs I can't really recommend anything - by the time I started writing those I'd switched to Scala (in which Spray is wonderful).


I'm with you that Spring has ALOT of parts. At my company they allowed us to use some parts of Spring and not others. Our stack was Spring MVC, with Apache Tiles, serving JSPs with some JQuery in there all wrapped up with Spring Security. It was much better than what we had before, JSF and ICEFaces and ADF. JSF frustrates me to no end.

Now we're moving towards a more modern stack. Using Jersey for REST is nice. It does make me enjoy Java again. You annotate resources in a Spring-like way, security was easy to implement. On the front-end we use a client side JavaScript Framework, JMVC (CanJS, EJS, etc). JMVC doesn't have as much traction as other frameworks, like Angular or Ember, but it is stable and covers what we need.

But when I go home, I try to stay away from Java. It's mostly Python (Flask, Tornado, Twisted) or lately some Node (Express) on the backend and Ember on the front. It's psychological. I program at work for work and at home to have fun. For me it just feels easier and more fun to stream code in Python.


For rest services in java I really recommend Dropwizard. Wraps a bunch of great libraries together with just enough glue to make your development easy. Really great support for metrics.


I while ago I had to choose a JVM based MVC framework to work with and originally I was looking at Spring. Needless to say it's a Mount Everest of frameworks, so by looking for alternatives I've stumbled upon Play. I decided to go the whole way and use Scala with it. Never looked back since. Typesafe stack offered me a rock solid Scala/Play/Akka/Slick stack with type safety, scalability, immutability, concurency that few others have (if any).


Modern Spring is quite nice, and after having tried Play, I go back to Spring MVC, but use Spring-Boot with Jetty was the embedded container.

Its much like Dropwizard, but better integrated with Spring if that is what you are used to or like.

No XML, and I can produce a usable web API with a minimal amount of boiler plate (its all wrapped up in Spring boot, much like Play wraps up a lot of stuff for you).


Yes, Spring Boot is pretty cool. Not a bit of xml in sight, unless you want it, of course. And you have the choice of deploying with an embedded Tomcat or as a more traditional war.

I think a lot of "big Java" haters haven't looked at Spring or JEE (which has seen similar massive improvements) in the last several years.


Nice! In the past I've used my own loader main to run inside Jetty, now I can just use this. I love finding cool java projs I've never heard of.


Not sure what version of Spring you are using, but the newer versions allow you to annotate your way out of the need to have so many XML files.

Code bloat is a different beast. Unless the company decides to refactor and redesign the whole thing, you probably have to live with it, like the rest of us.


Note that Play is only really comparable to Spring MVC, it's not a general-purpose dependency-injection framework. In the DI space Guice is more of a competitor to Spring.


Play is simpler compared to Spring but idiomatic Play code also requires you to learn reactive programming, something you probably won't do in Spring MVC.


Guice and SiteBricks [1] work very well together.

[1] http://sitebricks.org/


I was just recently trying to decide between "new" Spring MVC, Dropwizard, and Play.

Spring now has a bunch of slick-looking guides and tutorials. But then I looked at the actual contents of their tutorial project, and it just turned me off. For an "example" REST project, they had over 50 classes not including tests: https://github.com/spring-guides/tut-rest/tree/master/6/comp... , with many being "event" classes of some sort. I mean, WTF, is this really the "idiomatic" way to build Spring REST/MVC projects nowadays? I'm trying Dropwizard for now.


Been there done that. 3.5 years of Play 1, but they decided to rewrite it in Scala and I left in anger.

Nearly one year now of servlet dev, trying nearly anything I can get my hands on. Most I have been satisfied with is Restlet for service development, otherwise nothing even comes close to Play 1.

Finally decided to harden up and learn Scala. I have set my prejudices aside and after a month, I can safely say I am a _write_only_ Scala developer. I still can't read much of the fancy code in the wild, but for my immediate needs, gluing java libraries together, it's a far superior language to Java.

My opinionated guide to developing modern Java is: get TypeSafe Activator and learn Scala.


I actually started learning Scala: completed Odersky's Coursera class and developed a Play 2 project in Scala. Overall I like it, but reading others' code is often frustrating, shorthand shortcuts in language are still kinda alien looking, and even figuring how to handle simple things like multi-file upload with Play's controllers, I feel I don't quite understand what the hell is going on underneath all that magical functional code that I myself wrote by assembling bits and pieces from elsewhere.

And then I watch stuff like Paul Phillips presentations [http://www.youtube.com/watch?v=4jh94gowim0] and I just don't know whether continuing to invest my time in Scala is a wise decision long-term.

I'll probably try Clojure at some point, but for production-grade projects I will do Java for now. I feel the most frustrating thing about tech is having to place bets constantly on what to invest your time learning. It's eerily similar to investing in stocks. You never know what's going to live or die. And I'm saying this as a former Delphi developer with multi-year experience. :)


I started Scala from cold as it were without having ever done Java. I found myself having to read Scala code (source for things like Lift) 'backwards' to understand it. I read the body of functions from top to bottom but lines from right to left as maps/flatmaps make much more sense to me when picked apart that way. Maybe this is common/standard, not sure.


No, that example just covers more features, I guess typically you won't need events.

For a really quick start I would recommend https://github.com/spring-guides/gs-spring-boot/tree/master/.... 2 classes and you don't even need an external servlet container.


I'm using Dropwizard and it was easy enough for me - former .NET developer to get things done quickly. That said if I was starting today long term project I would go with Dartlang (yes they'are server side as well)


I'm using Dropwizard for the same reason. It is dead simple and gets me going out of the box. You should also give Grails a try if you plan on having a view layer


Dropwizard seems to have a view layer of its own that you can bolt on as well.


Yes it is just a binding between Jersey and templating engines (they maintain two of them: mustache.java and freemarker. I strongly recommend freemarker, since it is more complete in UI related transformations. This way it lets your Model layer to stay clean. But if you need something exotic, you can bind to your templating engine of choice easily)


Dropwizard is very nice. Can't comment on Play.


I think that to a certain extent, the standard library also encourages this culture, since that's the most prominent and arguably widely used piece of software that's written in Java and it will be used as an example of "good" code.

The continuing notion that CS classes teach objects first (I've heard recommendations that it be before even conditionals and loops, shockingly enough) I think is also a contributing factor: "When all you have are classes, everything turns into an object."

But as things like Java4K suggest, the bloat may not be inherent in the language itself; it's certainly possible to write concise, efficient Java code.


> The problem lies more in bloated frameworks...

How ironic... I was an early adopter of Spring, when it was all about simple "enterprise development without J2EE". So, given enough time, does bloat follow success and does it become inevitable?


One of my opinions these days on javadoc is that you should be minimalist. Have nothing to say about the return type? Don't add @return. Same for @param. Just a sentence about the method/field/class? Just a single line /* * ... */ is fine. Have nothing of value to say on a method/field/class (e.g. a getter), don't add javadoc at all. I'm growing weary of large files with tons of redundant javadoc lines to make some checkstyle/pmd rule happy.


Seconded.

I always bristle when I see javadocs that include things like 'returns an object of [x] type that...' You're dealing with strong types, the signature provides all this information already. That, combined with good variable names, should do a lot of the documentation for you.

If you wanna document a method, document what problem it solves. Document any gotchas (or better yet, redesign them out o_~). Don't just repeat what reading the method's signature already tells me.


Thirded. At my last place of employment I actually made this into an informal[0] coding style rule and succeeded in getting a few people to remove the completely useless default javadoc template which Eclipse (and the like) have for new methods.

One thing I did find very important was to document if your method had any side effects that were not obvious from just its name. (E.g. if a method is called printXXX() or logXXX() you can pretty much guess what it's going to do, but saveXXX() is a little bit more ambiguous. Where is it going to save things? The database? The file system? Is it atomic? Etc.)

[0] I don't believe in formal coding styles (at least not for small teams/orgs) since what constitutes "best" practice is always context-dependent. We handled all knowledge transfer (including coding style) by intra-team code review and a few very high-level documents about the overall system architecture.


Yet, I'm always surprised in how good the official javadoc is at avoiding this problem. They always have a @return and it's usually saying something useful. I think there's two situations:

1) You're writing javadoc for something that isn't really a public facing api. In that case, I agree, remove the @return. Perhaps even remove that / * * and convert it to / *. It shouldn't be officially documented.

2) It is public facing api. It may seem that the @return is redundant, but there's really a better way to document it.


That pisses me off but the following is much worse. The commit comment that goes:

"checked in abstract_class.cpp"

Duh!


I do that a lot, or rather my commit messages are usually "mumble" or "fixed this" or "awookga". I feel this is more justified than the javadoc case because you can always just leave out javadoc, whereas the VCS forces me to put a commit message.


Just a humble suggestion, but perhaps you should enter a message which states the intent or the functionality of the change more explicitly. (If you're just doing a topic branch, then sure, just say "wip" or "blah", but please clean it up with "git rebase -i" before merging.)


Yes, even something trivial like "fixes whitespace" is better then nothing, but even better is squashing or amending a previous commit. Some systems prevent this...at my workplace once you've pushed to origin, there is no changing the past so saying something like "Added derp.java to fix broken build from <commit hash>" is very helpful.


Always topic branches yeah. My team puts that kind of information in the pull request, which ends up playing the role that a commit would in SVN or the like. I guess we could squash our merges to achieve the same effect, but we haven't felt the need yet - the pull request is a nicer interface than a git log.


I sincerely hope that you and I never work on the same project =(


I've been guilty of that kind of comments you despise when I had to work in environments where software "quality" metrics were applied to all checked in code as a part of build process and your code was marked as "low quality" because you missed @return document entry in your Javadoc. You can bet that, with few IDE templates to autogenerate all missing JavaDoc on save my metric was quite good. In addition to that, I completely stopped trying to write good docs. What you measure is what you get in the end.


Yeah, I'm of the opinion that if you need a class/method comment to explain what it takes in or spits out, you probably named it badly.


Yes... mostly. I worked with a guy who, for every comment, asked "how can I eliminate the need for this comment?" Usually the answer is to name something better.

But sometimes you really need a comment, not because something is named badly, but because, even with the right name, there's something not obvious about it.


Agree completely, that's why I said "probably" :)

EDIT: Comments are useful for explaining things like:

1. Non-obvious side effects

2. Code that's working around a bug in a 3rd party library

3. Code that calls into some non-intuitive 3rd party API

4. Citing your work (e.g. "adapted from stackoverflow.com/blah123")

5. Why you used pattern A instead of the more standard pattern B


> But the modern Java developer uses Gradle

I'm a little skeptical of this. More like the developer in the future uses Gradle. Usually when I go to a project's home page, I see documentation on how to include the Maven dependency, not the Gradle dependency. It's pretty obvious how to convert one format to the other, but my point is I think most people are using Maven.


I'd say Gradle is the least awful of the 3 major build systems. Ant degrades into an unmaintainable mess as soon as any complexity enters the system. XML is a horrible scripting language, simple imperative constructs are very awkward (loops/variables/conditionals).

Maven also suffers from XML hell, but at least it has dependency management.

I've used gradle extensively and it is quite difficult to figure out what is going on. Using a debugger would be nice, but it simply doesn't work. Gradle is terribly slow on a big project, the update checks are the main culprit. They should be done automatically in the background to alleviate this pain.

Since gradle is compiled rather than interpreted, calling code in the project being built is difficult and convoluted. For example, if I want to call a DBUtil.cleanDB() method in my java code I can't reference DBUtil in my gradle script as it hasn't been built yet and the Gradle script won't compile. If gradle was interpreted this problem wouldn't exist....

I find the DSL unintuitive and the inability to specify the order of tasks execution is always a sore point.

On the positive, at least it's a language, not XML. I have never understood the java world's obsession with XML and forcing it in directions never intended. This XML obsession has led to java being a major laggard in automation tech. Java devs do many things manually that a Ruby/Python dev would be horrified at....


After doing couple of Android projects with Gradle I've felt like Maven is a godsend.

It might require writing some XML to declare what your project does, but at least it WORKS and at least it does not waste my time by forcing me to write code to include pieces of projects and properly process project (e.g. including native code, Robolectric testing, renderscript and some other things).

Also any compilation inside IDE's was orders of magnitude faster with Mvn than with Gradle... all in all setting up all the components with gradle took about 2-3x as much time. Mostly it seems like someone decided that because now you have code instead of XML for build configuration, they'll just skip most of the plugin design and force you to roll half of the build process on your own.

Right now (at least for Android), Gradle is a colossal waste of time due to lacking features, extremely slow execution and myriad of bugs which will eat away productive time on project.


> Right now (at least for Android), Gradle is a colossal waste of time due to lacking features, extremely slow execution and myriad of bugs which will eat away productive time on project

Are the sparse features, slow executes, and bugginess due to Gradle or due to the scripting language it uses? www.gradle.org/overview says they will happily support any community effort to create additional build script engines for Gradle. The Gradle developers had better do it themselves because after the Groovy++ fiasco, noone's going to put work into building something related to the Groovy ecosystem when it's likely to be skuttled and/or stolen later on.


I think it's just mostly the fact that tools aren't complete: e.g. IDEs will parse Maven pom.xml and use internal builders to speed up compilation while when using Gradle you're always spawning the external builder.

Same goes with other things: we had to write Groovy code to handle build cases which Maven plugins handle by default. That's mostly an ecosystem issue.


From the usual JUG discussion themes I also get the impression, if it wasn't for Gradle, the Groovy interest would be much lower nowadays.

There was a Grails wave here in Germany, but now I seldom see anything related to it.


Yesterday's Who is hiring? (https://news.ycombinator.com/item?id=7679431) only had 1 mention of Groovy or Grails (and none of Gradle) out of over 400 comments. And many (most?) of the projects tagged Groovy on Github are triggered by a single Gradle build script for a project that uses some other language. These Gradle build scripts are often 30 lines long.

So I'm not sure how Groovy will fare in the future. Nothing seems to be taking its place, though, for testing and general manipulation of Java classes. Java and Scala are statically-compiled languages for building things, whereas dynamic Clojure seems to also be used for systems programming rather than scripting. I'm guessing Oracle will heavily promote Nashorn for scripting and JavaFX, but Javascript syntax doesn't seem quite as full-featured as Groovy for now.


I seldom used it.

Back in 2009 there was a big Grails wave here in Germany. Many JUGs had Groovy and Grails talks.

There was also some people trying to use Groovy with JSF. Myself I attended a session promoted by Sun hitting at possible official support after the JSF 2.0 release.

To the point we added support to it in our in-house JSF framework SDK, still JSF 1.x based.

Since late 2010 I have been doing .NET land mostly and now back on Java land, I hardly see any Groovy besides Gradle.


for normal dependency management you shouldn't need to write code. I've never done any android dev, so I can't comment on that. declaring a dependency is literally like this:

dependencies { compile group: 'commons-collections', name: 'commons-collections', version: '3.2' testCompile group: 'junit', name: 'junit', version: '4.+' }

But I am not going to be the great gradle defender :) I have many complaints..... I would have much preferred that Rake became the default build system for java. Sadly that approach never took off....


Yeah, for normal dependencies that's true. But on Android you quickly get some additional things that have to be handled by the build system:

* Code generation from annotations (reflection on Android is slow, so doing code generation is way better) * Attaching native .so libraries in proper directories of APK (Maven plugin does that automatically, Gradle needed writing code for that to work) * Properly handling RenderScript backwards compatibility library (there was no Gradle support for that at all)

* Testing - Robolectric is still not supported which throws a wrench into whole Jenkins/TeamCity autotest stack and needs fiddling with emulators


> Maven also suffers from XML hell, but at least it has dependency management.

I don't find it that bad. The nice thing about it is how my IDE will auto complete almost everything and it should be possible to validate it without even using an IDE, as it has a schema. I agree with your complaints about Ant.

The thing I was hoping gradle would give me is the ability to write tests for my build. EG: I want to have more confidence that my maven filtering is working the way I want it to. But it sounds like gradle isn't built with that in mind.

Considering that groovy is dynamically typed, if my IDE doesn't auto complete (maybe it does) I think it's possible to make the argument that Maven is the least awful of the 3. At least the maven XML has a schema. I don't need yet another way to make a mistake in my build script (ie: typing issues).

> Java devs do many things manually that a Ruby/Python dev would be horrified at....

Such as?


w/ regards to gradle using groovy.... in gradle I can easily add in variables to my dependencies, I can write conditionals (if System Prop X then include dependency Y).

Basically anything you can do in code, you can do in gradle very easily.

Auto-complete does work in IntelliJ 13 - at least for groovy code type stuff. Nothing for the gradle DSL (that could be implemented of course).

> Java devs do many things manually that a Ruby/Python dev would be horrified at....

Jenkins config - almost every one does this by hand. Jenkins jobs weren't really even designed to be automated (ironic, eh), you have to build a full xml doc for each job rather than say apply a similar change across all jobs (add in a -D param across all jobs for example). I know this is a Jenkins specific issue, but this mentality is very common in java land.

Others: have every dev manually install a database for their environment (Chef/Puppet/Ansible solve this - and what are they written in? Ruby/Python)

No one would ever use java for any scripting type work, the JVM startup time is awful + the file/string libs are far less powerful/usable than ruby/python.

Of course a java dev can learn one of the scripting langs, but they typically don't.

this is just my experience, but note I've seen a lot of shops...


> I can write conditionals (if System Prop X then include dependency Y).

I stand corrected. That would be extremely useful. Maven is really awkard about these things. EG: "I want to run integration tests but not unit tests". Here's how: http://stackoverflow.com/questions/6612344/prevent-unit-test... Pretty lame.


A better solution is to use profiles.


Writing tests for your build script is an interesting idea. I wonder if this would be easy to do in something like SBT where the build definition is itself an SBT project.


Declarative builds = intelligent tooling. Would json make it better? I hate editing json too. Personally I would go with toml but wait... that would look similar to something else...

Ant's real problem is that it never found a path towards next generation. Why isn't ivy included by default? I want something bigger and easier to use that isnt gradle or maven but is more along the lines of an Ant+ivy default. It should have a bootstrap script, it should understand default project directories... It should continue to be declarative, but it should have an xsd or similar descriptive format that can be used for tooling.

There is a future in the ant+ivy perspective that I don't see in other build tools.


Actually, Maven uses XML right - as configuration, not code. This is where Ant was terrible - you ended up writing imperative code with XML statements.


Ah see I know you aren't an intellij user because your "XML hell" comment makes no sense.

IntelliJ makes this a breeze. I'm sorry you aren't using it, that must make life really hard :-(


that's absurd. 1) I can't embed code in XML. 2) Why should I use a format that takes 5x as much space to declare something as a more usable format?


Agreed. On top of which XML has no capacity for logic, barring an incredibly contrived construct.


What kinds of logic are you putting in your builds? That's a sign you are doing things wrong.


hmm I wonder why this got created? http://ant-contrib.sourceforge.net/tasks/tasks/

I wonder if anyone said this about HTML when javascript was introduced?

once a system starts getting complicated you inevitably need code.

two points:

* gradle builds can be completely declarative. you write code only if you need it

* builds also are often used for very specific automation. in ant, you end up having to write custom ant tasks. this is fairly painful compared to just creating new classes, tasks, or scripts directly in gradle.


I often find that "can be declarative" means that over the long term in a big project means "isn't declarative"

After all you can do functional programming in any language. Why do you need another.


Specifying the dependency in Maven XML has become sort of a standard that even Gradle people use. Obviously, Maven has been around much, much longer, and a lot more people are still using it, but more and more are switching to Gradle. At the very least Gradle has come to a point that you don't have to worry about it not being maintained, or that there won't be people to ask if you've got a question.


There are no winners in the build war despite the overwhelming online support for Gradle. Personally I'm not a fan of it. I find it on the slow side even compared to maven. I'd rather have declarative builds like Ant but therefore support better tooling than super freeform tools like Gradle that force you to drop into a language with about as much type safety as Javascript. Multi-project builds are also annoying, as Gradle has to parse and validate all the connected projects before proceeding with one single task on the build you're invoking due to its design. Very annoying stuff.


The performance problems are definitely the most annoying part of using Gradle. The Gradle daemon helped a little but tended to break other things and Gradle was still pretty slow.

If you are looking for something faster and more declarative, you may want to check out SBT[0]. It is way faster than any of the other JVM build tools. Also, in the future[1] it should have much better tooling support than anything else on the JVM.

[0] - http://www.scala-sbt.org/ [1] - https://github.com/sbt/sbt/wiki/Client-server-split


Right now, SBT + IDEA is a bit of a pain because they share the same target folder and IDEA sometimes overwrites/deletes .class files that your application (started via sbt run) hasn't loaded yet. Usually that leads to a few ClassDefNotFound errors and such. Hopefully that'll go away once we have a single SBT instance.

My two wishes for SBT would be: 1) A monadic style for .scala build files. It would make dealing with the immutable bits of project definitions so much more pleasant and we could avoid the weird semi-Scala syntax of .sbt files. And 2) A bottom-up approach similar to Pants. My team frequently end up getting a lot more project interdependencies than we bargain for simply because it's too easy to induce transitive dependencies.


Would you mind elaborating on what you mean by a monadic style for .scala build files?

PS - You may already know this, but you can change IntelliJ's compile output directory [0].

[0] - http://www.jetbrains.com/idea/webhelp/configuring-module-com...


Thank you, I haven't actually tried that. I really live the "I just want my IDE to work" philosophy (out of laziness), so I try to avoid configuration if I can. :)

About monadic style: I realize that it's a hard sell, but it's basically about leveraging for comprehensions (aka. do-notation) to specify your build. Shake is an example of this, although probably not particularly suited to building Scala code.


Shake?


Sorry, should've linked[1]. There's also a further link from there to a paper for your reading pleasure :).

[1] http://hackage.haskell.org/package/shake


Thanks!


SBT has a terrible habit of breaking backwards compatibility, which has put me off it.


I've never had to change anything between upgrades (aside from changing deprecated stuff). Are you referring to the jump between from 0.7 to 0.10 a few years ago or have you had more recent issues?


Yeah, I just went and had a look at the project in question and I'm being unfair to SBT, it was a plugin I use to package WARs that changed underneath me. The plugin was quite closely coupled to the version of SBT, but the latest variant of it (once I found out about the migration to a different artefact) seems good.


> I'd rather have declarative builds like Ant

Is that a typo? I'd say Ant is the opposite of declarative.


It's interesting. Ant is a somewhat constrained imperative language. Gradle is a highly constrained declarative language built on top of, and with an escape hatch to, a completely unconstrained imperative language.

If you stay within the bounds of that the Gradle DSL can do, rather than throwing Groovy around (which is possible - i write a lot of Gradle, and very rarely write raw Groovy), then Gradle is rather nice and easy to reason about. But if you don't, well, you're going to have a bad time.


I've definitely found gradle to be faster than maven, particularly using the daemon, and even more so considering the extensive support for understanding when a task is up-to-date. I haven't run a clean task in gradle in several months, but in maven it seemed to be a crapshoot if the clean was required or not. That saves a lot of time.


You should be skeptical. Many Android projects don't use Gradle. Gradle itself might be stable but Gradle issues are at the top of every single Android Studio release notes.

When that stops happening I'll start thinking about Gradle.


Gradle is mainly being pushed by Grails and Android development.

I don't know of any other project using it. We are always doing Maven or Ant.

If Gradle is the future I hope it gets improved, I gave up on Android Studio given its dependency on Gradle and how it drags my dual core with 8 GB to its knees when compiling.


> I gave up on Android Studio given its dependency on Gradle and how it drags my dual core with 8 GB to its knees when compiling

That could be the slow, dynamically-typed Groovy in Gradle that's dragging your machine. Gradle needs to bundle another build language. Since the goal of statically-typed (and hence speedier) Kotlin is to make it easier to write IntelliJ IDEA [1], on which Android Studio is built, instead of using Java, the logical choice is Kotlin.

Gradle's developer says they'll happily support any community effort to create additional build script engines other than Groovy, but it isn't a priority for them right now [2]. Perhaps the Kotlin team need to kick off a Kotlin build engine for Gradle (though because one of the Kotlin developers was a victim of the Groovy++ fiasco, I'd understand if the Kotlin people are hesitant about having anything more to do with Groovy ecosystem software like Gradle).

[1] http://blog.lunatech.com/2011/08/24/scala-ceylon-kotlin-goal...

[2] http://www.gradle.org/overview


Kotlin was exactly the reason I was thinking to move from Eclipse ADT to Android Studio.

So far I have been using the Eclipse ADT/CDT for my hobby development, mainly with C++ (just graphics stuff).

Then I thought to try out Kotlin instead, but could not. It was worse than waiting for my NDK C++ builds to finish, with the whole computer at 100% CPU usage.

I ended up filing a ticket, like many other developers already did.


https://github.com/search?q=gradle&type=Code&ref=searchresul...

I also know that Netflix use Gradle for pretty much all their Java stuff.


Spring is pushing it hard in all their new tutorials, even non-Grails. Which annoys the heck outta this Maven guy.


Is Grails really pushing Gradle adoption? My experience has always been that the integration between the two is pretty bad. Are things better now that they finally... released a real Gradle plugin to support Grails 2?


That was my perception. I don't have Grails experience.


Southwest Airlines uses it.


libGDX (cross plattform game lib.) also made a push to gradle


Because of Android moving to gradle I would say.


They tried maven first, then gradle. Their build is pretty customized, so gradle makes a bit more sense.


And Minecraft Forge.


Personal anecdote, I stopped trying to develop for MC Forge in version 1.7 because the gradle build they switched to was unbelievably slow and difficult to use. After several days of poking it, I still couldn't understand why asking gradle for a simple list of available tasks was taking >10 seconds, and when I tried to give my workspace to a friend on another computer, I discovered I had totally I failed to get a list of coherent commands that I was 100% sure could reproduce my workspace on a new machine, because of large amounts of scattered hidden state I had failed to detect. Part of this might be poor build config design, but gradle certainly helped enable a lot of poor behavior and certainly doesn't impress me with its performance for trivial tasks.


> I'm a little skeptical of this.

The title did warn that it is an opinionated guide.

I think most projects that used Maven before Gradle don't have enough incentive to migrate. A lot of the new projects, however, start out with gradle: Vert.x, Crate.io, RxJava.


This. I can't see myself using Gradle any time soon. Literally everything I've touched is maven only and I don't want to learn another DSL on top of yet another language.


Yep, Maven is the defacto AFAICT. But so is Java 6 currently.


The #1 thing you need to make Java usable is to abandon the JavaBean conventions. When every field requires 8 lines of boilerplate it's no wonder the code looks ugly (YAGNI, and if you do need it it's two keystrokes in your IDE to "encapsulate field"). public final fields are fine, and can get your data classes something close to readable.

I'd stick with maven for the build rather than Gradle; it's completely declarative and all the tools understand it. Learning a new language just to configure your build tool seems excessive.


For starters, you can see Groovy as "Java without semicolons". I went from Maven to Gradle and never looked back. It's superior in most ways. The tooling could be better though.


> For starters, you can see Groovy as "Java without semicolons"

Not if you have to read other people's code, or understand examples you find on the internet.

> I went from Maven to Gradle and never looked back. It's superior in most ways.

What's it better at? I want my build tool to be simple; maven compiles my source and does my releases, and the main thing I have to configure is just a list of dependencies (in an admittedly verbose format). I'm actually a scala programmer, but I use maven rather than SBT because it seems to me that having lots of logic in the build system could only lead to bad things. So what are the things you see it helping with?


See my reply to vorg regarding Groovy. As a developer the argument "I don't want to learn something new" is invalid.

Gradle offers the declarative nature of Maven without pushing it down your throat. You don't have to write a plugin for something that can be expressed in 3 lines of Groovy (but you can, if you want to!). Instead of adapting your build to Gradle, Gradle adapts to your needs. That's often a point of criticism from Maven users, because every Gradle build looks different. But that's the point: Everyones needs are different. Of course that only applies if your build is beyond the standard compile/test/release configuration. A simple configuration looks pretty much like a Maven POM (minus the tag soup).


Maven is simple as long as your build is simple. As soon as you need to do something custom, it's a pain. Gradle is less painful.


> you can see Groovy as "Java without semicolons"

Only a very small subset of Groovy is used by the typical Gradle build script, the very subset of Groovy that's least like Java. What part of this build script from the linked article bears any resemblance to Java?...

  apply plugin: 'java'
  apply plugin: 'application'

  sourceCompatibility = '1.8'
  mainClassName = 'jmodern.Main'

  repositories {
    mavenCentral()
  }

  dependencies {
    compile 'com.google.guava:guava:17.0'
    testCompile 'junit:junit:4.11' // A dependency for a test framework.
  }

  run {
    systemProperty 'jmodern.name', 'Jack'
  }

  javadoc.options {
    docletpath = configurations.markdownDoclet.files.asType(List) // gradle should relly make this simpler
    doclet = "ch.raffael.doclets.pegdown.PegdownDoclet"
    addStringOption("parse-timeout", "10")
  }

  run {
    jvmArgs "-javaagent:${configurations.quasar.iterator().next()}" // gradle should make this simpler, too
  }


I understood the post I replied to as if the author wanted to configure something custom and thus needs to write code. I didn't assume that the original argument was supposed to address the configuration of a standard build. Because you'll always have to learn a new syntax for the tool. Use Make-> Learn make syntax. Use Maven-> Learn POM syntax. Use Gradle -> learn the DSL syntax. Want to extend Gradle -> learn Groovy, a "superset" of Java.


I'd submit that the POM "syntax" is much simpler than a full programming language.


You don't have to learn the complete XML syntax to write a POM. Think about it.


I think anyone programming Java is going to have to learn XML pretty soon; not so Groovy.


Modern Java is usually 100% XML free. Even new servlet containers/standeard REST frameworks (Dropwizarrd, embedded Jetty etc.) require no XML whatsoever.

You only need XML if you're deploying to heavyweight servlet containers (standalone Tomcat, e.g.). Even embedded Tomcat doesn't use XML.


That's not what I wanted to point out. To write a POM, you don't need to know the XML specification. If you want to write a Gradle script, you don't have to know Groovy. You just have to use the Gradle DSL which is fairly compact for most plugins. You make it sound as if you have to learn a whole new programming language, and if that was the case I would agree that Gradle sucks! If you want to do something more specific, then yes you will have to learn Groovy, but at that point the time will be spent well. Also, most of the time Groovy is weakly typed Java with lambdas and no semicolons. I think you've already spent more time arguing about not wanting to learn Groovy than time you would've needed to learn said amount of Groovy.


Maybe you can write it, if it's a solo project with a fairly vanilla build. But as soon as you have to collaborate with other people, or read examples from the internet, you're going to run into full-on Groovy; "the Gradle DSL" is not well-defined, so while most bloggers will claim they're writing idiomatic Gradle, they'll all have different subsets of Groovy in mind when they say that.

By contrast Maven has a very rigid format - there's no risk of randomly seeing a lambda or conditional expression in the middle of the XML - and its plugin model ensures that there's a very clear delineation between what's standard and what's an extension.


The "Gradle DSL" and Groovy's grammar are the same thing, mixed together in one Antlr file, and probably the largest programming language grammar I've ever seen. Here it is for Groovy 1.8, the version that shipped the paren-less parameters that Gradle uses:

http://svn.codehaus.org/groovy/eclipse/trunk/base/org.codeha...


I accept that argument if you prove my preceeding argument, that you don't need all of Groovy to use Gradle, to be wrong.


> you can see Groovy as "Java without semicolons

I see it as "Java without types", myself.

I'm aware that Groovy now supports optional typing but if I'm going this path, I prefer to switch to Kotlin, which I describe as "Java with everything that's bad removed".


If that's what you want wouldn't Ceylon be a better choice? If you're still using the Java standard library you still have the billion dollar mistake (null) everywhere.


Project Lombok is your friend then: http://projectlombok.org/features/Data.html


Until you have to debug it. At which point you realise you're now writing what's effectively a different language with its own tooling and compilation (and its own bugs), and if you were going to do that then you might as well go all the way to Scala where you get much more in return.


Lombok is an anti-pattern for me. It creates a unholy mess of annotations for what should be language features.


I used Project Lombok back in the days to get read of Javabeans boilerplate. Just declare your private fields and put @Data annotation on class, and it would generate at compile time all your getters, setters, equals, toString, constructor and hashCode methods. Really helps to keep the code lean and small. Don't know does it work with Java 8 though or it didn't yet catch up.


I used Lombok in a Java 8 project without problems.


Couldn't agree more. Use public, protected, private fields as they were meant to be used. I only dip into JavaBean anymore if I need a readable but non-writable field.


For me that's almost all fields: I try to make just about everything immutable by default. Makes reasoning about concurrency much simpler.


For immutable you can just use public final fields. I assume GP must be talking about fields that are mutated but only by the object itself, where outside code needs to be able to read but not write.


Not quite. eg:

public final Date date;

date.setTime(1);

That's not immutable.


The bean convention doesn't help you with that one though; if you have private Date date; public Date getDate() {return date;} then people can still do getDate().setTime(1);


Yeah, but with a getter you can make getDate return a copy of the Date object to enforce immutability.


Yep, the thing is that Date is immutable. I think that this public final immutable rule is ok, but one has to ensure the fields themself are really not modifiable.


The Java Date class is not immutable.


So you can use a wrapper or Joda time library.


A class with mutable fields that a caller can mutate is not immutable.


Yeah, but getDate().setTime(1); works the same way.


Not if getDate() returns a copy of the underlying member.


The fact that java.util.Date is terrible is so many ways should go without saying.


Couldn't agree more.. But this comes with the most cliche discussion with a smartass looking at your code. Dude, I know what getters and setters are, I just don't agree


I'm using Java for the first time because of Android. I had played with Java when it first came out but have stayed with C/C++/C# for almost everything.

I have to say that my Java experience isn't as unpleasant as I thought it would be. I always thought C# is what Java should have been but after learning a little idiomatic Java the reality is quite okay, really.


The way you phrased that sounds to me like you've been programming for a significant amount of time. If that is the case, the Java of today offers so much that a younger Java did not, and I suspect you would have had a more unpleasant with the java of 10 years ago.


In a lot of ways C# is still a much superior language than Java, but the JVM (I'm thinking HotSpot) is tremendously better than the CLR.


I follow Grail and now Truffle development since the days of the Maxime VM.

Looking forward to the day the reference JVM becomes a meta-circular one.


Anyone looking at where "enterprise" Java went - the whole J2EE monstrosity - would have run screaming. But the basic language is actually quite good and has been for a long time.


That pluggable type system looks amazing. One thing that's weird to me is how java included a new Optional type (seems similar to Haskell's Maybe), but the compiler (afaik) doesn't prevent you from setting an Optional field to null. Something about that doesn't feel right. (Side Note: Optional isn't serializeable. Also... what's the best practice for using Optional when I'm using JPA? Can it be used in my Entities?)

I believe Jetbrains/Intellij-IDEA has created annotations for @NotNull/@Nullable, but afaik these just create warnings in the IDE. Maybe you can configure IDEA to mark these as compiler errors, but I don't know if my peers using netbeans/sublime/whatever would be able to notice when they write code that IDEA will refuse to compile.

I want compilation to FAIL in these cases.


The main issue with non-nullable types in OOP, in my mind, seems to be defaults. Quite simply, when you don't initialize an primitive, you get a 0, and when you don't initialize an object, you get a null. Not all fields must be initialized by the time the constructor ends, so some kind of valid default exists.

Enforcing non-nullability would involve somehow enforcing that the variable is always valid before use some other way, like how "final" is enforced in the constructor, but it should be possible.

Unless you make it default, though, it won't be as "elegant" as the haskell Maybe, and doing so would net you a very very different language.


Outside the JVM world, Eiffel does it.

In the JVM world, Kotlin and Ceylon do it as well.


There are a number of implementations of JSR 305 (https://jcp.org/en/jsr/detail?id=305). Findbugs is one that provides the annotations. You can include the annotations JAR file on your compile path and then use findbugs in your build to enforce them. IntelliJ will still recognize them and flag the warnings/errors.


It's certainly a bit strange, but it's how Scala works as well. I wonder if it's for backwards compatibility reasons, given that everything is nullable already. Have to give it more thought though.


Indeed, Option in Scala has the same problem. I understand null is needed for backwards compatibility, but it makes Option the poor man's Maybe...


> Indeed, Option in Scala has the same problem

eh?

    scala> val safe = Option(null)
    safe: Option[Null] = None


I don't understand your objection:

  // The type of 'unsafe' is Option[String]
  var unsafe = Option("some string")
  unsafe = null
  unsafe map println
gives

  Exception in thread "main" scala.MatchError: null
effectively a NullPointerException. This would be impossible for a true Option (aka Maybe) type. The problem is introduced because Scala, for backwards compatibility reasons, still allows the assignment of null; this lowers the usefulness of pattern matching against Option types.

--

edit: you could object to my use of var (and you should). Ok, let's re-write it to be a val:

  def unsafeFunction(x: Option[String]): Option[String] = {
    x orElse null
  }

  ...

  val unsafe = unsafeFunction(None)
  unsafe map println 

...and I still get the NPE. Note that in this case you can easily see how I introduced the problem, but the point is that the signature for unsafeFunction should guarantee null is not a possible return value.


    // The type of 'unsafe' is Option[String]
    var unsafe = Option("some string")
    unsafe = null
    unsafe map println
Is complete contrived nonsense, var? Seriously, quit trolling, in Scala (immutable) val is king.

Next:

    def unsafeFunction(x: Option[String]): Option[String] = {
      x orElse null
    }
Oh yeah, that's brilliant, let's just try our hardest to come up with scenarios that never occur in the "real" world (unless we try really hard to create nullthing out of nonething).


I'm not trolling. I genuinely want to like Scala, which is why I'm disappointed by some of its design choices.

Yes, in Scala val should be king (unfortunately, it's not -- if you've taken the two Coursera courses by Odersky you'll see some use of var in the exercises, refuting your claim). But it's true val is more common, and the use of var was accidental to my point anyway (mutation wasn't the issue), hence my clarification and second example. Yes, it's pretty obvious where I introduced the mistake, I said as much. In the real world, the mistake might be harder to spot, which is why the type system shouldn't allow it.

If I understand your position correctly, it seems to boil down to "programmers will code correctly, therefore this static check (that Option must not be null) isn't needed". Which is pretty much what dynamic typing proponents have been saying all along. A pretty untenable position if you want to stay on the side of Scala...

I'd much prefer if Option were more like Haskell's Mabye, but then again, I side with static typing. I understand why, given Scala's requirements, this wasn't possible. It's just disappointing.


There's no need to be disappointed in Scala's Option, if used sensibly (i.e. not intentionally trying to break it) Option will work as advertised.

val is indeed king, var is used sparingly, look under the hood of any prominent Scala library and you'll see val-ue of immutability put into practice. Locally scoped vars can be useful, but beyond that dangers waits (not unlike Haskell's unsafePerformIO).

In terms of disappointment, I could say similar things about Haskell: I'm deeply disappointed with the eternal compile times, meaningless stack traces (no line number, heh, nice), non-existent tooling (read: null IDE), etc.

Scala lives on the JVM and has seemless interop with Java; concessions have been made, the type system will never rival that of Haskell, but then again, outside of Haskell no other mainstream language's type system rivals that of Scala.


Fair enough. I don't believe Option is only broken when "intentionally trying to break it". Of course, my example is trivial and the null is explicit. But what if it was a call to a Java method that shouldn't return null, but does because of programmer carelessness?

I agree there are pain points with Haskell as well, no language is perfect. But slow compilation... surely you're kidding when you don't see this as a problem with Scala? The compiler is SLOW. And as for IDEs, which one do you recommend? I heard good things about IntelliJ, but please don't recommend Scala IDE because to say it's inadequate would be a huge understatement. I've cursed too many times with its phantom compilation errors.


Reason appears ;-)

When calling a Java method assume a null return and wrap it up in an Option just as you'd do with Haskell when interfacing with the "outside" world.

As for Scala compilation speed, Haskell's not gonna win that battle, ghc is to scalac as scalac is to javac, which is to say, the last is first and the first is last in terms of compilation speed. Also, IIRC only Yesod provides incremental builds, no? With SBT incremental builds most code changes incur a < 1 second recompilation hit.

As for the IDE story, the secret to a performant Scala IDE is to turn off automatic builds in Eclipse and let SBT run the show. With the SBT eclipse plugin there's a setting that allows SBT compilation target and Eclipse target to be shared so you never have to clean/build in Eclipse -- this is a huge win, the difference between standard dog slow Eclipse performance, and snappy, oh this is real nice if only the haters knew, joy ;-)


I'll try that, thanks for the recommendation!


  scala> val x = Some(null)
  x: Some[Null] = Some(null)


That's pretty contrived, when would you _ever_ wrap a thing that could be null in a Some?

Even so, to continue with your example:

    scala> x foreach println
    null

    x.get
    res2: Null = null
Hey, what do you know, no NPE.

Try harder ;-)


Ok fair point re it being contrived!

Although (having just re-read it), the original post's complaint was actually that:

> the compiler (afaik) doesn't prevent you from setting an Optional field to null

ie

  scala> val option: Option[Any] = null
  option: Option[Any] = null


Exactly, that was my complaint. It makes elegant pattern matching against Option types (the whole point of using them, in fact) less than useful. Now, in Scala-land, you have to check that they aren't null, which sucks.


This complaint shows pretty well that some people have never actually used Scala.


Can you elaborate? The whole point of Option types is that I can map (for example) over them without explicitly checking what their value is, and it will work without a runtime error. Same with pattern matching.

With the introduction of null, this is no longer possible. I've just shown an example of getting an NPE while mapping over an Option[String]. Now we're back in Java-land, where I must explicitly check for nulls, read the source code of every method or trust some comment that tells me that it will never return null. (Ok, not exactly like Java-land: a Scala programmer who returns a null for a function with type Option is very inexperienced or is doing something naughty. But why does the language even allow it?)

Aside from telling me I'm wrong, can you explain why?


Scala needed to support null somehow in order to interoperate with arbitrary Java code, such as passing null as a parameter to a third-party Java library. So at least some variables should be allowed to have null. Maybe they couldn’t think of a way to prevent Option-typed variables from being null without preventing arbitrary Java interop. Making only Option types reject nulls might have been thought too hacky.

Those are just my guesses of the design rationale, working from the fact that Scala does support nulls. But perhaps Scala could have come up with a better solution that still allows null use when necessary. If you think of some syntax and elegant semantics for allowing you to forget about null for most code, I’d be interested to see your proposal.


Oh, I understand why null was needed (backwards compatibility, like you said), and I'm no language designer, so I don't know what I would have done instead. Maybe mark pieces of code that must interact with Java code with "unsafe" blocks, outside of which no nulls can escape?

  unsafe {
    ...
  }
Don't know if this would work. I'm just disappointed because this slightly breaks the Option type, that's all.


> I'm just disappointed because this slightly breaks the Option type, that's all.

I have never ever seen this happening.

The complaint feels a lot like "well, someone could use reflection and change the cached values of Integer, why don't you check that every time something returns an Integer?" to me.

null is the sad fact of running on the JVM, but pretending that it doesn't exist works 99.9999% of the time in Scala.


I know I'm beginning to sound like a broken record, but "I have never seen this happening" is a poor argument when discussing type systems. Please realize that "I've never seen a type bug like this happen" is exactly what proponents of dynamic typing will say when dismissing the burden of static typing: "I've never seen a bug caused by incorrect types. It sounds nice in theory and in your contrived examples, but in practice type errors never happen to me, therefore I don't want a type system that gets in the way."

The fact is that type system should NOT allow an Option val to be null. That's what type systems are there for. If a Scala programmer coming from a Java background wants to use null in Scala programs, the compiler will happily allow it. This is awful practice in Scala, of course, but it's allowed without warning. I've seen this happen with amateur Scala devs (and I'm ready to admit I'm an amateur with Scala too, I don't want to sound condescending).

Your remark that "null is the sad fact of running on the JVM" was what I was saying all along. Am I allowed to express disappointment that Scala's type system is compromised because of this fact?


> Your remark that "null is the sad fact of running on the JVM" was what I was saying all along. Am I allowed to express disappointment that Scala's type system is compromised because of this fact?

What I'm saying is that you are barking up the wrong tree. You need to go to Oracle and complain there if you are unhappy about nulls.


I agree that the design is a result of trading off the desire to do away with nulls vs retaining Java interoperability. Preventing (at compile time) only Options from being null is surely impossible when casting/reflection are available.

It is commonly understood that if an API returns Option[A] then the client can assume it will not return null. Personally I have never experienced a real error from this.


You can at least add runtime assertions automatically with jwtbrains annotation processor (maven plugin). I don't know about compiler errors,


A lot of people love to hate on Java, but it's a surprisingly dynamic language and there is a ton of great testing, networking, and many other libraries available.

One of the things I appreciate about Java is the ability to take large teams and just have their stuff work together, without having unhuman discipline around super subtle rules (eg: C++)

Also, IntelliJ is a must have!


In what way is Java a "dynamic language" ?


Contrary to popular belief Java is highly dynamic. You can introspect the fields, methods, interfaces of any object at runtime, inject new / redefine classes, methods, fields, etc. The problem is that it's very awkward and unwieldy to do so. Hence the tendency to build new JVM languages rather than attempt to use Java's dynamic features directly.


I think "dynamic platform" would be more accurate. Java has typically been a fairly conservative language sat on a much more interesting VM, a VM which has rather more features in common with dynamic languages like Smalltalk than you'd expect.


but you can always escape with cglib and rock out.

So even though java the language isnt dynamic, you can do a lot more at runtime, than with these new-fangled languages like Go and Rust.


Java has a lot of runtime knowledge about itself, it can do a lot with that.

As a result, you see things in Java that are more typical of dynamic languages, rather than C++ for example.


"Dynamic language" != "Dynamically typed language".


I think he meant dynamic as in ability to adapt rather than a dynamic language like python


> super subtle rules (eg: C++)

C++11/14 is in practice not that much more difficult to write well than Java. It's not 1998 anymore.

The language is larger and more complex than Java, but it's also a lot more expressive and powerful, not to mention faster.


Exactly. I'd argue C++ has a lot going for it, and I think the claim that Java's performance is only slightly slower is simply not true for the vast majority of situations where good memory organization can provide significant speedups - which includes any computer graphics, vision or audio application.

I personally find C++11 more high-level than Java and significantly more optimizable for performance.

You can wax poetic about "developer time is more important than processor time" all you like, but when your application runs like a turtle on anything short of server-class hardware, it doesn't mean much.

Performance will always be of primary importance for a large class of applications. For the rest, Java is a good alternative.


Java is fast enough now to compete with C++ in some categories of software traditionally viewed as "high performance" e.g. web-servers or database systems. Applications running like "turtle on anything short of server-class hardware" is a result of bad-coding, not Java itself.


In some categories, yes.

In many others, especially those requiring vector or matrix arithmetic (medical imaging, physical simulations, modeling, graphics, scientific computing, video games), there's simply no competition.


Not sure of that. Some scientists from CERN would certainly disagree... Pure array-based arithmetic in Java is pretty damn fast, especially if you care to avoid dynamic allocations. It can be also very memory/cache friendly.


I was under the impression CERN was a C++ shop, have they switched over to Java?


They do have quite a few projects in Java and they published some of their Java scientific libraries as open source. See Colt project. Also the software processing data from LHC is at least partially Java based.


In anything where Java approximates the speed of C++ it uses two or three times as much RAM.


10 millions element array of doubles/ints/bytes takes almost exactly same amount of bytes in Java as in C++. Java can blow your memory if you do stupid things like wrapping every point 2D into a separate object, but you know, good Java programmers know this. Other than that, its memory usage is quite reasonable, including some room for GC (typically 20-30% of total is enough).


Having spent 5 years doing production C++, I don't believe you basically.

All that shit that sucked in 2005 about C++ is still in there. It's just up to your discipline to not use it.

Do you trust your coworkers enough?


Yes. Basically, don't hire incompetent people and do code reviews. Both rules apply independent of the language, of course.

Source: have spent 5 years doing production C++


You still have to read Effective C++ to avoid shooting yourself in the foot, but after that C++ isn't much more difficult than Java or C#. The compile times remain annoying, though.


> C++11/14 is in practice not that much more difficult to write well than Java. It's not 1998 anymore.

While I agree with you and C++ belongs to my favorite languages, the truth is that most corporations still use C++98/C++03 and they aren't going to improve their compilers any time soon.

On our Java projects we still get requests for Java 1.4.

The enterprise is a very slow moving snail.


Its having the knowledge of what subset of features do you stick too, because C++ is quite large feature rich language. There are often many ways of doings things.


One of the reasons I love programming in Python so much is the focus on idiomatic code and 'one obvious way to do something' means that unfamiliar codebases or APIs are easier to read, and patterns for common tasks are seen again and again.

More

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: