Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Better Java – Resources for Writing Modern Java (github.com/cxxr)
202 points by networked on Sept 19, 2015 | hide | past | favorite | 188 comments


"If you're using Java 8, you can use the excellent new Optional type. If a value may or may not be present, wrap it in an Optional class like this"

While I agree with most things, overuse of Optional like this is an antipattern IMO. Having done a lot of Java 8 development, I find Optional is best for return types, but otherwise forcing callers to wrap values in Optional is unnecessary as opposed to something like Scala. Those that work on the JDK feel the same [1][2] and I think [2] is even overuse with the prevalence of static analysis tools and @Nullable.

Although a tad dated, I find [3] to be a good guide to modern Java all around.

1 - http://stackoverflow.com/questions/26327957/should-java-8-ge... 2 - http://blog.joda.org/2015/08/java-se-8-optional-pragmatic-ap... 3 - http://blog.paralleluniverse.co/2014/05/01/modern-java/


Have to agree here. The article's use of Optional is well intentioned, but shows use of the construct in a way that it was not intended. It should be used minimally, and only as a return value to signify the absence of a value. When you notice that Optional is not serializable, this starts to sink in.

Here are some more thorough treatments: http://stackoverflow.com/a/23464794 http://blog.jhades.org/java-8-how-to-use-optional/


Watching the evolution of languages / APIs makes me believe that Optional over-use is a necessary step between "our language has no formal Optional therefore crash" and "our language uses null in a sane manner".

C#'s prior behavior gives me hope for languages I'm currently paid to care about like Java and Swift on this issue.


When I get some time I'll update the OGMJ. I think the choice of tools mentioned is still very much up-to-date, it's just that some of the APIs used in the examples have been upgraded.


I really like OGMJ, it's definitely a great resource and I recommend it to many new Java developers; however, I disagree re: tools mentioned.

After trying dropwizard for a few projects, the superiority of the spring-boot and its various ecosystems just blew me away.

Also, while I appreciated Gradle, Maven is just much more supported through the entire eco-system. As a new comer to Java from C++/Python, it made a big difference.


You're probably right about Spring Boot. I've never been a web developer, and TBH, I've had no direct experience with either Boot or DW other than a simple Hello, World. At the time DW seemed the safer choice simply because it used the JAX-RS standards, and using standards in the Java world (especially good ones like JAX-RS) is a very good idea. But in the meantime Spring Boot has also done the right thing and adopted JAX-RS (at least as an alternate API), so I should add it to the post.

As to Maven vs. Gradle, that turned out to be the most controversial point of the entire guide -- which surprised me. Let me put it this way: both are good and I prefer Gradle. Also, Gradle, while still far behind Maven in terms of adoption, has good momentum. Either is a good choice at this moment, but I would guess that Gradle will take the lead in five years (although it's far from a safe bet).


5 years is a long time in IT. Gradle has a millstone called "Groovy" around its neck because of an early poor choice to ship with only one configuration language. Maybe they'll enable more languages to be plugged in later on, but there's an ex-Pivotal programmer who used to work on Groovy now working at Gradleware on Gradle who might sabotage such an effort because of his lingering association with Groovy.


> Maven is just much more supported through the entire eco-system

Could you give some examples? I haven't had much problem with Gradle support, and Gradle's essential advantages over Maven fat outweigh what little I have had.


Keep in mind that Tony Hoare, the inventor of the null pointer, calls this invention his billion dollar mistake. I generally think that he is right and use of null should almost always be avoided.


By all means, have more clumsy, less straightforward ways to represent the lack of a value in your code, because Tony Hoare says so.


An Optional type is more clumsy than null checks and null returns sprinkled everywhere??


The problem with NULL is that it can be there for literally any reference in your code. So, unless you are careful, you can get an NPE when calling any single object method. In languages without NULL this can never happen making them much easier to reason about.


My initial reaction: programming ain't bean bag. Them's the breaks.

Then I think of it and I see the real problem is languages making all nonprimitive types into pointers without being explicit. In a language like C it's more obvious what can be null.


If null can be problematic then certainly making it more obvious when you might have a null is a pretty good idea. I tend to think, however, that getting rid of null completely as a concept is even better. One less thing to worry about.


A NullPointerException is unchecked as well. I would say about 40% of our code is checking for null to avoid NPEs especially with APIs. You have to protect yourself and cannot take nothing for granted.


Despite what he says, I don't think Hoare actually invented the "null pointer", as address 0 for "not exists" or "end of list" was probably a common convention ever since linked structures existed and independently discovered by many others. (The other convention would be the all-bits-1 value, but I'd assume that testing for 0 was easier and thus more widely adopted. Also, "0 = nothing" makes great sense.)

IMHO Optional just feels like another typical Java dogmatic overabstractionism. "Null pointer exception? So what? Just catch it." Then again, I mostly use C/Asm.


Given that the Option type has existed in programming languages other than Java for decades I don't think it makes sense to call it a "typical Java" thing.

I can see how a C/Asm programmer wouldn't like it though. Very different mindsets. :)


The difference is that other languages which originally had the Option type don't have null, so it's the only option. I meant it's typical of Java to take features from other languages, resulting multiple slightly-different-but-incompatible ways to achieve the same thing.


I certainly agree that Java would be a much better language if NULL could be eliminated completely. Backwards compatibility though...

sigh


Yeah, Optionals came from other languages, not originally Java.

IMO the problem with Optionals is that they'll never suffice unless they are part of the language itself, like in Swift. As this article pointed out, Optionals aren't supported in any existing APIs, so you still have to do a ton of null-checking everywhere. And there is nothing that guarantees an Optional reference itself can't be null, which is why you really want language-level support.


I'm probably being a bit too pedantic here, but strictly speaking they don't need to be part of the language at all. You just need basic support for (generic/parametric) algebraic data types.

For example, Haskell has Maybe which is not part of the language nor treated specially by the compiler in any way. It is part of the Prelude (think "standard library"), so that (basically) all libraries can agree on what "Maybe a" means.


In other paradigms (Lisps) null is a lot less than a billion dollar mistake, it seems it goes better with map/filter/fmap patterns. In imperative languages, data is tied to control, and null means segfault.


When some ELisp code crashes in my emacs with an error like:

  error: (stringp nil): not a string
I think it indicates Lisps suffer from this problem too...


It does, I said 'a lot less' not 'zero dollar mistake'. Recursively defined lists take care about nil, and since it's one of the most used ways to program in lisp it makes a lot of logic nullproof.


I'm also not a fan of passing Optionals into methods. Most of the time it's easier and cleaner just to write an additional method without that optional parameter.


It can grow cartesian though.

I think the best compromise is to declare a new data type for the argument, such as:

  data ExecutionDirectory = ExecuteInCWD | ExecuteInDir FilePath
And take an ExecutionDirectory instead of a `Maybe FilePath`.

Of course, you need light-weight data declarations for that.


I'm curious, which aspects of An Opinionated Guide to Modern Java have dated?


I've seen numerous posts lamenting the use of typical Java Beans.

The problem with the struct approach is that numerous tooling / libraries expects beans with typical getter/setters - Jackson Json, Spring binding, etc. Yes it's possible with configurations and/or annotations to get around this, but IMO, saving a few lines of code in exchange for non-default behavior isn't a valid trade-off.

Adding a dependency on Lombock is even worse.

Honestly, I can spot a Bean class within 1 second of opening it up. Unlike Scala or other languages, Java programmers typically use one class per file, and beans rarely get in the way as they're typically contained in some 'model' package anyway.


Another problem with struct approach is inconsistency.

Sometimes you want a computed property and you use non-trivial getter. Sometimes you want to do some work in setter. And then client's code will look terrible: point.x * point.x + point.getY() * point.getY(). There are other problems: binary incompatibility; non-trivial refactoring when I need to introduce a getter or setter.

Java really need lightweight property syntax which would solve all those problems. I don't understand why it isn't introduced yet.


I'm surprised I haven't seen anybody mention the "public final fields" approach yet. I use this myself for immutable objects and I quite like it. Granted, you still need to implement equals and hashcode, but these can be generated easily and verified with tools like EqualsVerifier [2].

[1]

  public class MyImmutable {
    public final String field1;
    public final int field2;

    public MyImmutable(String field1, int field2) {
        // assign
    }

     // equals, hashcode, toString
  }
[2] https://github.com/jqno/equalsverifier


Projects exist to to make a light weight property syntax. The most prominent might be @Getter and @Setter from lombok (https://projectlombok.org/), but there are others which have similar goals (e.g. http://immutables.github.io/, https://github.com/google/auto).

That said, I agree that java _really_ needs something like this built in.


The lack of simple property syntax is probably the main reason I keep using Groovy now that Java 8 has arrived. Yes, state is evil. But there are still plenty of situations where you are just schlepping data around and generating thousands of lines of boilerplate to achieve simple data transfer is such a pointless and ugly hack.


For DTOs we don't user mutators. Just public member variables. It is the only way to keep business logic out of them. That being said, I wish Java has some object/struct syntactic sugar like Javascript Object Literals. They are so powerful.


> Sometimes you want a computed property and you use non-trivial getter

Then pre-compute it, make it immutable, and expose the variable. And if that ends up being too hard it's probably because you need a builder and/or to group your properties into smaller classes.


Precomputing properties on a hundred million object instances is not cheap.


Going from C# to Java, one of the biggest things I miss is the Property syntax.


C# property shares its own set of issues , especially when there are exceptions involved.


> Spring binding

Not sure what in particular you're referring to, but Spring supports constructor based dependency injection, and I tend to insist upon it vehemently - getter/setter injection means that you can instantiate your object in an invalid state.


Lombock is one of the most valuable enhancements to Java. Without it, it would make Java development not as fun.


Lombok is also a non-standard dependency and there are costs with having to rely on it.


If the cost overweights the benefit you can delombok everything will works as before.


The problem comes when you spot a Bean class and then it isn't. 99.9% of "getX" methods simply read the field. But if you assume that every "getX" method just reads the field, you'll be caught out by the rare one that doesn't - I've seen a production bug happen this way.


Also, whatever stylistic issues are raised by JavaBeans are largely obviated by modern IDEs.


I'm surprised he didn't mention AutoValue [1] or Lombok (using @Data and @Builder) in his section about data objects and builders. I prefer AutoValue, but both approaches cut down on a lot of the boilerplate (and they also generate sensible equals(), hashCode(), toString(), etc).

It's also kind of a nitpick, but I disagree with his preference for Guava's Maps.newHashMap() vs new HashMap<>(). I'm pretty sure the only reason those static methods exist is because pre-Java 7 didn't have the diamond operator.

[1] https://github.com/google/auto/tree/master/value


Immutables (http://immutables.org/) is another option which creates nice, immutable value classes. It's a bit more succinct than AutoValue, but it does still require annotation processing in your IDE.


Lombok's a bit sketchy as parts of it rely on some undocumented, non-standard parts of the Sun Java compiler - you have to be really into code generation to want to use it.

Other libraries like Immutables are safer for this purpose.


He mentions Lombok in the tools section.

And Guava's collection creation methods are part of an intense desire to not use the new key word anywhere in application code.


Also, if you look at the Javadocs for some of the creation methods, they explicitly state that they are for Java 6 and earlier, and that modern code should just use the constructor with the diamond syntax.

http://docs.guava-libraries.googlecode.com/git/javadoc/com/g...


The other replies kind of hit on this, but I'll expand on it by saying:

The collection creation methods existed because Java could perform type inference on methods but could not on constructors:

  // Java 1.5
  Map<String,Integer> map = new HashMap<String,Integer>();
  // Guava
  Map<String,Integer> map = Maps.newHashMap();
  // Java 1.8 diamond notation
  Map<String,Integer> map = new HashMap<>();


I realize he mentions Lombok, but he specifically bemoans the extra boilerplate with writing builders and data classes, but does not mention the @Data or @Builder annotations...


Wouldn't the best way to create an empty map be to use `Collections.emptyMap()`?


After working at two companies filled with Java devs, I don't think any of them will read this article. I can't speak for all Java devs obviously, but it seems unless the dev is a polyglot, they are just fine living in their Spring/SVN/J2EE/Java5 world. They have no idea what's going on in the software development world. I get so excited whenever I hear any of them mention Clojure or even Scala! They just live with this head in the sand mentality. They hate the front end, they think, "these JavaScript developers will go away someday and we can finally go back to writing JSPs". Currently we've updated our JVMs to 8, and that's a big deal, but we've told our devs NOT to use any features from 8 as we're worried about how GC will perform and since we're about to get geared up into shopping season, now is not the time to use shiny new features.


This is also how I feel with PHP Developers who work in development agencies or larger companies, either in a small team or by themselves (probably even larger teams, but no first hand experience with that).

Basically they refuse to use version control (FTP their code to the live server), use a terrible dev system, non-existent or terrible staging environments or newer technologies such as composer or other tools which will save them time and effort.

Don't even get me started on the lack of tests, and how buggy and broken their code ends up being - "we don't have time to write tests", yet spend weeks fixing critical issues that would have been found...

/rant


I see the lack of unit tests constantly. I did a small stint with PHP and one of the first things I did was learn PHPUnit. Having invested heavily in the TDD Koolaid with Rails/Python, I made sure I learned how to apply the same ideas in PHP. And yes, I've seen quite a bit of the "1999 was just fine" culture among PHP developers too. If you can't deploy your code at the touch of a button, you should be working your way to that goal.


On the flip side, the best practice for both Java and PHP is trending towards the same thing. Routes + DI + immutable types + fluent api's. Give it another decade and the only way to tell the difference will be the presence of $ characters.


That's a shame. Java is my favorite language because it has the right balance of strictness (although Go is starting to take over for me). When written correctly, Java can be amazingly productive because you learn so much at compile time but the tools (IDEs) make it so that you can autocomplete away most of the verbosity.


Java as a language is totally fine! It has everything one might need. The culture totally sucks. Oracle leads the march toward what is the "standard". Jersey is a great leap out of this.


I consider Jersey to be a good example of what is wrong with Java. Annotation driven APIs don't really lend themselves to composability - sparkframework, vertx or ratpack are much better ways of building REST apis with Java 8.


Using the annotations could probably be done a different way, but it follows many of the popular micro-frameworks like Sinatra for Ruby, or Express for Node.js.


Java lacks higher-kinded parametric polymorphism.

Java also lacks the ability to say something like:

  class Foo<T> implements ISerializable iff T implements ISerializable
So you end up having to work only with T's that are serializable, or not having the instance for Foo.

Also, Java lacks type-classes.

Java also lacks lazy bindings, and many other useful features one might need.

In short, Java is still very far from having everything one might need...


What do you mean by: "you learn so much at compile time"?

I'm a C and C++ guy, but I've done a tiny bit of Java a while ago.


A lot of mistakes are picked up before the devs can even compile their project. (Note that I did not say "you". I guess pro C and C++ coders are a lot more thoughful about their code and therefore don't that level of static checking.)


Mentioning Scala, or clojure or even Haskell to a HR interview leads to raised eyebrows at best. But that was expected. I'm surprised actual devs are still wearing eye blinders.


I'm hiring front end JavaScript developers right now. If I see other language experience on their resume, they're getting a call. My last hire had worked through "Learn You A Haskell" and that was enough for my interest to be piqued. Seeing Python, Ruby, C, ObjectiveC, heck even PHP is enough for me to see they're not just a "I did some Angular tutorials" type of candidate. I'm on this site, so I get a nice smattering of different technologies. I don't write Rust, but I know it exists. I've read about it. Same goes for a ton of other technologies/languages/methodologies that I don't deal with. It just floors me that anyone in the development/engineering world doesn't do the same! They must believe their language/tech will exist forever.


I've always been surprised when I run into developers who really don't have an interest in multiple languages, platforms, whatever. But, I think it's something you come to understand, that every profession has people that are just phoning it in every day. Some of the best people I've hired have had no experience in the one technology that I'm hiring for, but their enthusiasm and level of interest has been more than enough for me to want to take a chance on them. It usually works out well.


I should have added that it was IT consulting shops HR I was referring to, not final clients. The further away from the actual jobs, the more buzzwordy it gets. Some might appreciate curiosity and diversity, but in the end they want simple and bankable. They told me, some missions will enjoy jack of all trades type, but the majority of their clients wants framework-specific forces.


I have a hard time believing that a company stuck on Java 1.5 or SVN is like that because the developers want it that way.


Even worse, the Java 1.4 world. I've seen people avoid generics and other Java 5+ features for "compatibility reasons".


Wow, you didn't even get forEach with 1.4, right???


People get in the habit of writing loops with indices.


I still people doing that shit in Java 8 and Groovy... I can probably count on one hand the situations when a counter-based loop is necessary.


> I can probably count on one hand the situations when a counter-based loop is necessary

Such counting is analagous to counter-based looping. If you'd said "I can probably filter down to the fingers of one hand..." I might have believed you.


What a curious comment. The first portion of your diatribe disparages all java developers, but the latter part of it suggests that you're still working in java shop (perhaps in an ops capacity?) I'm wondering what you meant by JVM 8 because no such thing exists (unless you were talking about the JDK or the JRE.)

You must have worked at some sweatshops to spout such biased vitriol.


Well, I was an English major, so I'm glad you were engaged by the "diatribe". And if you were unable to piece it together... and I kinda feel bad if you couldn't. I'm referring to Java 8 language features and OpenJDK 1.8. I get the feeling you knew that though and are being pedantic. You've succeeded though, because I responded.

Sadly you missed the part where I said, "Not all Java devs obviously". I have read great blogs by Twitter engineering and many others.

But, since you seem to have some experience in sweatshops, please explain how your current situation is different. Add something to this conversation instead of correcting my stupid generalizations.


Your comment about the "JVM update" was a non sequitur trailing from your rant, but I'm glad to know that you were indeed referring to JDK 1.8. The fact that you get excited in the event these nebulous java devs have "heard" of Clojure/Scala only comes across as patronizing (but I suspect you weaved that in masterfully and deliberately, given your degree in English.) Your anecdotal fallacy hasn't added anything valuable to this conversation (your parent comment admittedly claims the original having "stupid generalizations"). Most of the other comments here on HN are discussing specifics outlined in the article, but it's evident that you don't have anything meaningful to contribute in that area, which is a shame because it appears that you value polyglotism so one would think you could offer your "enlightened" perspective around best-practices which could help the community in a more meaningful way.


Your comments in this thread violate the HN guidelines. Please comment civilly and substantively, or not at all.

https://news.ycombinator.com/newsguidelines.html

https://news.ycombinator.com/newswelcome.html


You have won at the internet. I'm sure you're a joy to be around. I haven't seen the meaningful response that you've added. You really do seem like a troll. If that's not your intention, that's cool. If it is, well, hey, happy trolling dude!

Edit* Yep, just checked your comment history, you're a troll. God why do people like you exist.....


Personal attacks are not allowed on Hacker News. Regardless of whether you think someone is trolling, a comment like this makes the thread obviously worse. Please don't.


Agreed, may I edit or delete this response?


We're always happy to help with that, but can you please email hn@ycombinator.com about it? And thank you for the polite response—I really appreciate it.


While you're reviewing these, you should probably take a look at your original post which got you in this thread of poo-flinging to begin with. It doesn't address the article at all. It just says 'grumble grumble, those Java people!'. It's content-free flame bait that produced predictable responses such as 'And those PHP people!' and 'I'm a Java person and you, Sir, are an ass'.


But this is the point. Now you've felt the need to teach a lesson... which also has nothing valuable to add. I feel like any conversation on Java or newer Java does lend itself to my point. If we can't add any personal experiences to these stories, then why do we have a comments section? I know it's not just so we can post links to other facts. And no, I'm not stuck in this thread. I'm trying to do the fair thing and remove a response to a personal attack and name-calling (which was mine). I stand by my initial statement. I work in an environment where a ton of Java devs don't understand why the pesky front end people keep asking for these RESTful JSON APIs. "Why can't we just do some JSPs and give you an XML/XHR when you need a hint of dynamic-ness?"

This is what brings on personal attacks. The attitude in which you post. If you fail to see my original point, ask for clarification. It would have caused me to edit my original and change my tone.


The point was 'if you don't want to feel embarrassed by things you post in flamethreads and have moderators berate you, don't start flamethreads', that is all.

Take a look at the top comment in the thread for a) an actual substantive criticism of the article b) a link to a much, much better survey article on the same topic.


There is some good stuff in here, and a lot of bad.

SparkJava (mentioned) is the great hope for sane java web development:

http://sparkjava.com/

Having to convert out to streams for data structure manipulation with lambdas is insane. It would have been very healthy for the core java team to pull in someone with a lot of ruby experience so they could get that API right.

Too bad: the JVM and associated tools are fantastic.


> Having to convert out to streams for data structure manipulation with lambdas is insane

I don't see why. It's explicit and allows you to chain higher order methods without building up a ton of intermediate data structures and convert to any data structure you like very efficiently.

It's still not efficient as imperative approaches but it's close enough and far better than most collection libraries.


Have you seen Goldman Sachs collection library? I've been using it for my Java work for last year and found it to work well. Put's a lot of useful methods onto the Collection objects themselves.


Please don't use Java 8's default methods in interface's to do multiple inheritance, and code reuse. Prefering this over 'Util' classes is bad as it is inheritance over composition. The default methods were designed to facilitate easier interface migration


That reminds me of "constant interface" anti-pattern - abusing a feature because it brings a small technical benefit.

If you are unhappy with candy-shop utils class and are ready to split them into smaller entities, go the whole way there. Create proper small classes, and inject them using your chose DI technology.

Anyway, kudos to the author, that was a risky article to put together and there was no way to write it without controversial recommendations. That's a good start for what a new java developer need to look for.


Inheritance over composition. I know what these words mean, but I don't see your meaning.

Also, I don't think that's what default methods are for. The new StreamUtil libraries uses default interfaces. It's not migrating anyone, but the default methods describe intrinsic properties about the classes that inherit the interface. A predicate can be in sequence of another predicate, for example.


Java was designed for TV set-top boxes, but that doesn't mean it's bad to use it on a server. If using a default method in an unintended way leads to clearer, more maintainable code, do it.


how would it lead to more clearer code? You would have many interfaces referencing an instance variable, each with different semantics for that variable. Interfaces cant have variables so they should not be used as traits.


One good use case I can see is where you want to add convenience "helper" methods to an interface that can reasonably have default implementations in terms of some other method on the interface (E.g. overloads to emulate default parameters). Or for methods that can be implemented in terms of another method, but might have a more performant direct implementation (e.g. Collection#get can be defined in terms of iteration).

I don't quite understand your point about instance variables. Instance variables are and should be encapsulated. An object that implements multiple interfaces must of course provide the correct semantics for all of them. But that's true whether an interface contains method implementations or not.


I'm in agreement with the first few comments already - at least some parts of this advice is dubious.

For one - some performance examples (specifically, integer array iteration) is 15 times slower with streams.

Angelika Langer's analysis:

https://jaxenter.com/java-performance-tutorial-how-fast-are-...


>For one - some performance examples (specifically, integer array iteration) is 15 times slower with streams.

That's a very misleading example, and even the linked post itself explains why it is so (e.g. not much is done with the integers in the first place).


I would question these results. I ran the same code on a more modern processor (i7-3930K) for 1000000000 iterations and got these averages over 10 loops after a warm-up:

Array: 453 ms Stream: 887 ms Parallel stream: 120 ms

The array loop code is about twice as fast as the sequential stream (parallel stream blows both of them away). The array loop advantage will start to go away once you increase the complexities of what you're doing in the loop and, of course, the stream code is much more readable.

(Edit: I also tested IntStream().of() instead Array().stream() for the sequential stream test, the results were identical in both cases.)


My solution is to use Groovy wherever possible. It has a superb syntax, very low learning curve and compiles into JVM bytecode. There is no issue with getters and setters in Groovy - you just define the fields, which Groovy calls properties and defines implicit getters and setters.

If not for the main application code, I would definitely use Groovy for unit testing in combination with Spock Framework. You just have to try it once to realise what you've been missing all these years with JUnit.


Groovy's always been OK for quick and dirty testing of Java classes, though the statement label hack that Spock uses makes Groovy look trashy. The static compilation that came with Groovy 2.0 is what no-one should touch if they don't want to spend countless hours and days debugging and wondering why they didn't use a language built from the ground up for static compilation, e.g. Java, Scala, Kotlin, Ceylon, and others.


One thing I'd add, is that Java is very amenable to static code analysis, and there are good tools like PMD and FindBugs for Java. I always encourage teams using Java to use one or both. The biggest downside is that you usually have to tweak the rule-sets to avoid getting lots of false positives. And if you get too many false positives then people tend to stop paying attention to the notifications from the tool.

On a related note, I really encourage Java teams to shoot for a goal of having compiles that finish with no warnings. If there are generic warnings littering your code (like, for example, all the warnings about unqualified references to generic types that you get when using code written before generics existed), bite the bullet and either fix them, or make it explicit that you don't care and add the appropriate annotations to turn them off. At least that way, when a new, interesting warning shows up, maybe people will pay attention to it.

And yes, this is something of a "do as I say, not as I do" thing, as I have definitely written Java code that doesn't follow this rule. Especially on my personal projects or code where I'm not working with a big team. On bigger projects, I do try to push that as much as I can, depending on my role on the project.


> [...] Java is very amenable to static code analysis [...]. The biggest downside is that you usually have to tweak the rule-sets to avoid getting lots of false positives.

These two statements seem to be in opposition to each other.

(All your advice is spot on. If you let warnings remain in code, you'll just end up accumulating more and more warnings until it's too much to fix. I guess it's a sort of "broken windows" effect.)


I don't know if they're in opposition exactly. The Java language is definitely amenable to static analysis to some extent, probably more so than a more dynamic language. But a lot of the "false positives" are just about what rules the developers of the tool ship by default, and what they define as a "bug" (or "possible bug"). For better or for worse, static analysis tools sometimes conflate simple stylistic issues ("don't use variable names less than two characters") with things that are likely to be actual logic errors. And since the tool will always be limited in how much it can understand about the intent of the code, it's pretty much always just applying heuristics and a probabilistic analysis, even when processing Java.

So yeah, those tools aren't perfect, but my subjective experience has been that they help, as long as you tweak the knobs so that they don't just generate something equivalent to the "broken windows" compiler warnings, etc.


My point was basically that, in general, imperative programming languages (like Java) are insanely hard to do static analysis on, so I though it was ironic that you mentioned that it (Java) was both a) amenable to static analysis, and b) said that it resulted in a lot of false positives. I think that point b) somewhat invalidates point a), don't you think?

EDIT: False positives tend to indicate that there's something wrong with your analysis.

I suppose this is a general thing: If a warning system alerts you every five minutes, what are you going to do? Are you going to react and go on full-adrenaline-rush every five minutes, or are you just going to turn it off after two or three false alarms?

EDIT: Sorry, OP = you. Edited correspondingly.


>> Good alternatives to using Spring is Google and Square's Dagger library or Google's Guice. They don't use Spring's XML configuration file format, and instead they put the injection logic in annotations and in code

Spring has had code-based configurations since 2009[1]; seems a little disingenuous to recommend Guice/Dagger due to this non-existent limitation.

[1] http://spring.io/blog/2009/12/22/configuration-simplificatio...


Spring has a million and one ways to do anything; that's the problem with it.

Spring with a very strict, carefully enforced style guide is probably as good as Dagger or Guice. But there is a cost to maintaining and enforcing a style guide. Better to just use something that doesn't have the bad options.


That's what Spring Boot is for.

Everything is autoconfigured and set to sensible defaults. All the dependencies in the starters are levelled and guaranteed to work together.

Spring Boot on Gradle is the closest thing Java has to adding lines to a Gemfile in a Ruby system. Especially when you add other Spring automagical libraries (Spring Data REST, Spring Cloud...).


Not sure how you get that reading... the author makes no claim that Spring is limited to XML configuration. In fact, in the paragraph just before the one you quote:

> It [the Spring framework] has a either code-based wiring or XML configuration-based wiring.


I read the paragraphs a little like "Spring has code-based config and xml-based config (careful with the xml-based config!) Guice and Dagger don't have xml-based config, so use Guice or Dagger". My gripe is with the hand-wavy treatment of why Guice/Dagger are better alternatives just because they don't have xml-based configs even though the author knows that people can use Spring exclusively without xml-based configs (this is why i said it was disingenuous)


This is a really great resource and I'll certainly be embracing some of it.

I attend quite a few university hackathons as a mentor/sponsor and one of my goals has been to paint Java in a better light as it doesn't have the best reputation in that circuit. I'm always telling people that their goal should be to build something cool and learn something new.

It's much easier to teach someone how to build their first webapp in a weekend when you can do it in a language that they are familiar with and Java seems to be what's taught at most universities.

The Spark Framework mentioned here is very well done and beginner friendly. I recently wrote an intro blog post [0] about it as an attempt to embrace existing knowledge and showcase that it's easy to build something cool with Java.

0: https://www.twilio.com/blog/2015/09/getting-started-with-gra...


Looking at Spark framework I'm wondering about your thought of Spark vs Spring Boot. I've not used Spark but I find Spring Boot lets you get an app of the ground quickly, is part of massive Spring ecosystem which gives you a lot of other advantages (for example, Mongo template might be very useful for Hackathon project). Beyond that RestController automatic integration with Jackson can quickly let you bring up a JSON based webservice.

Also I'm not a fan of how in your example the entire app routing/logic is basically crammed into a single main method. I know it might be simple demo app that you're trying to show off Twilo but I don't think you're doing favor by structuring like that.

What do you feel are the benefits of Spark vs Spring Boot (or Dropwizard I guess). In my mind the only reason I wouldn't use Spring-Boot for a new project in Java is if I wanted to use something like Play! since supposedly using Play!/Scala and futures integrate very nicely into that.


I mostly agree with this list but some things I have issues with.

The biggest is DI. Having witnessed what a tangled mess large Guice codebases can become where you really have no idea what is providing what I have to say that Spring here gets a bad rap from the all-XML days and (IMHO) it is actually the cleanest and easiest to work with.

The author mischaracterizes Spring too:

> It has a either code-based wiring or XML configuration-based wiring.

Actually Spring can use a mix of XML code configuration and auto-wiring.

A modern Spring application will have precisely an application context XML file with one line per "bean" eg:

    <bean class="com.foo.SomeClass" />
and that's it. Note: there's no classpath scanning. Auto-wiring takes care of the rest. This has two big advantages (over Guice in particular):

1. Everything is in one place. If it's not instantiated here it doesn't exist. Guice can be many levels deep and tends to descend into ModuleBuilders and conditional logic in modules (which the docs recommend against but tends to be used extensively anyway); and

2. Testing. Testing is incredibly easy. I'm talking functional testing here, even integration testing. You simply include another XML file that overrides any definitions from the first. Everything else remains the same.

Testing with Guice can be horrendous and once you start making extensive use of Modules.override() you should abandon all hope.

I'm glad to see this post recommend Maven. It's fun to bash Maven but most detractors ignore the huge benefit that applies to any shop with lots of devs: Maven is opinionated. That's a plus not a minus. Seen one Maven Web application and you've seen them all. There's no really weird directory layout because someone decided they just had to be different.

Lastly Play. I really tried to like Play. I really did. But as of Play 2.0+ it became a Scala not a Java framework. It may still work with Java but some things just require you to know something about Scala. That's a huge negative IMHO. I'm not interested in Scala. Nobody is.

Plus the auto-compile feature of Play tended to randomly break with indecipherable error messages for no readily apparent reasons such that you couldn't tell if it was a bug or not. I get enough of that with C++ template programming thank you.

I also agree that the two books the author recommends are probably the two most important Java books in existence.


> Scala. That's a huge negative IMHO. I'm not interested in Scala. Nobody is.

Their use of Scala was the only reason I gave the play framework a second look. Just because you're not interested in Scala doesn't mean nobody else is. Scala is the most popular plugin for intellij by a very wide margin, that's a lot of 'nobody' downloads. Having used both java and Scala extensively I honestly can't understand why anyone would still pick java by choice other than if it's the only jvm language they know.


> 1. Everything is in one place. If it's not instantiated here it doesn't exist.

But that one place is XML. Better to have it be code, where I can use all my normal tooling ("find references" in my IDE (yes some IDEs have spring support), grepping through .java files, automated refactoring...) to work with it.

> Guice can be many levels deep and tends to descend into ModuleBuilders and conditional logic in modules (which the docs recommend against but tends to be used extensively anyway)

Have you seen the kind of horrors that are possible in Spring XML with conditionals, proxying, interceptors...? Compare like with like.

And in the worst case, if you must put conditional logic in your config, at least if it's in code then you can unit-test it the normal way.

> Testing. Testing is incredibly easy. I'm talking functional testing here, even integration testing. You simply include another XML file that overrides any definitions from the first. Everything else remains the same. Testing with Guice can be horrendous and once you start making extensive use of Modules.override() you should abandon all hope.

Shrug. Not my experience; you get more-or-less equivalent tooling capability with both (that is, you can group your definitions into smaller modules, and you can override specific instances when testing), so if you use them the same way it'll be just as easy or hard.


> A modern Spring application will have precisely an application context XML file with one line per "bean" eg:

I prefer my Spring applications to look like this:

    @SpringBootApplication
    public class Application { ... }


On the struct-like data objects part - this is so much nicer than the getter (and setter for mutable objects) pattern, just because readability is so much improved.

Getters/setters is a pattern that it took me a while to reject, having always been told that public fields were really, really bad. But they're simply not. Having logic in getters/setters is the only justification for this added bloat. In my experience, in the overwhelming majority of cases (never say all) having logic in getters and setters is a clear indication that your design is flawed anyway, so most of the time you should never have them.

On this part:

> Further, this class is immutable unless you extend it, so we can reason about it easier as we know that it can't be changed.

Well, I'd go further. Make the class final if you really want to guard against people extending it. Of course this is most applicable for writing reusable libraries where communication with consumers may be limited.

If you rely on language features to enforce development practices in a team who can freely communicate, in general you've got a much bigger problems than the few rare bugs that extending an immutable class and making it mutable will cause.

Obviously though, putting guard rails in can only ever be helpful, even when absolutely everyone understands that there's a cliff edge there, and wouldn't conciously try to walk over it anyway.


I don't like to use getters, setters either. I like default package access so instance variables are just visible inside a package.


I used to be a fan of the Builder pattern (or Fluent Interface), but the ease of use for developers comes at the cost of no compile-time checking. Before, you just had to look up the constructor to see which parameters go where, with the benefit of type-checking. Now, you have to look up the Builder's methods to make sure you've filled in all required fields. The only case where I can actually advocate using Builders is when you have a mess of telescoping constructors.


If you have this problem, the library you're using is incorrectly using the Builder pattern. All required parameters should be in the constructor of the builder. Then the other methods on the builder should be optional configuration. For instance on Android you often see a builder that takes a `Context` in the constructor because that's almost always required.


This is contrary to the OP's example, where he passes data and num to the constructor, which is how I've seen it used frequently. The Builder pattern is often recommended to "make code easier to read" and wouldn't be useful if many/most of those parameters were required.


You can have a type-safe fluent Builder, but it requires having one or more static nested classes with private constructors. The outer class will not have a build() method, but rather that method will live in one of the nested classes. You use the type system to control what parameters have already been set, and what parameters need to be set.

Obviously, this can apply to many sorts of fluent API. This is at least part of what Tony Morris is alluding to in his essay on API design [1].

[1] http://blog.tmorris.net/posts/understanding-practical-api-de...


> Now, you have to look up the Builder's methods to make sure you've filled in all required fields.

the builder should fail with a good error message if there are required fields you didn't supply to the builder.


This doesn't solve the problem where the parameters aren't checked at compile-time. Now, hopefully all your codepaths are tested so your builder doesn't throw exceptions in production.


If you have required parameters in a Builder, you're doing it wrong.


Re the first bit about 'struct' style, even better (IMO) is to use Lombok; throw an @Data annotation on your class and all you need to do is put your properties in there (private final if need be). Nobody should be writing those boilerplate constructors, getters and setters. If it's generated by your IDE, use Lombok. The best code is no code.


Lombok is a crime. Have you seen what happens when someone does a minor reformatting of your code and moves one field declaration above another? You get a nasty little surprise because the two fields of the same type have now reordered in your Lombok generated constructor. When the app runs nobody can figure out why foo is set to bar and bar is set to foo. There's also the issue of Lombok vals which don't conform to the language spec leading to other fun. And it's almost always incompatible with new jdks without code changes to the lombok libs due to the whacky way it relies on implementation specific compiler details.


Wow, I didn't know this could happen. I've only recently started using Lombok for some side-project related stuff and this heads up comes at a really good time. Thanks!


Thats one of the things that'll happen to you if you start writting groovy code. The whole setter/getter boilerplate thing gets really annoying.

Another groovy-ism.. the whole deal with having to copy properties. (In a groovy class they're threated like a map)


> properties. (In a groovy class they're threated like a map

Except in hard to remember special cases like .class which gives the class "LinkedHapMap" of the map object instead of the value at key "class". After working with Groovy for a short while you'll realize you're really working around it.


then you suddenly force anyone who uses your code to depend on lombok. I tried to find a compile time only mechanism for lombok - not sure i found it, but it ought to exist!


Lombok does rewrite bytecode at compile time only. Your dependencies will not have to depend on Lombok.


As a fan of immutable objects, I bemoan the builder pattern. The nice thing about constructors (or factory methods) is that you have a compile time guarantee that you have all required components to construct an object and validate its invariants. With a field oriented builder, only the documentation informs you whether you've met all of the conditions to construct an object. Also, a builder which mutates its own internal state breaks the idea of partial application where several variants can be constructed from a parent.

Unrelated to builders, the stream example could be simplified further with method references

    final List<String> filtered = list.stream()
        .filter(s -> s.startsWith("s"))
        .map(String::toUpperCase)
        .collect(Collectors.toList());
It would be nice if Oracle back filled some predicates to make them more useful in streams (e.g. "s"::isPrefixOf, etc.).


You can create immutable "builder" with lambda chains. This also gives you the compiletime guarantee that you have specified the required fields (At the cost of flexibility and ease of adding new fields)

http://benjiweber.co.uk/blog/2014/11/02/builder-pattern-with...

Regarding your isPrefixOf - is there a significant benefit to that being in the standard library? You could define a isPrefixedWith("s") that returns a Predicate<String> yourself.


This is great, thanks. I've also used something like this: https://gist.github.com/dwijnand/3741951


The Builder pattern includes setting sensible defaults on the built object before building it. You configure the built object in the constructor of the Builder, before anyone starts updating fields.

You can achieve this through constructors or setters; Builder itself is agnostic.


Streams are questionable in performance vs non-stream approaches. I haven't found an article that details performance differences, but I will say that I personally tried doing things using streams and doing the same things using non-streams and have had mixed results, one being faster than the other in some cases.


The benefits of streams isn't performance improvements for the CPU, but performance improvements for the developer.


i have colleges that claim streams don't necesserily make the code more readable. Imagine a triple nested for-loop - making it a triple nested streams (e.g., where your map method is yet another stream), doesn't seem to really make it any more readable.

The only reason to use streams, i think is the possibility to automatically parrelize, and secondarily to make it more readable.


I would take any triply-nested for loops, and reduce each loop to its own method. Inside that method would be nice, easy-to-understand stream logic rather than for-loops.

The Java compiler will unroll the methods anyways, so you get easy readability without any loss of performance.


95% agree with these opinions, but have a few disagreements, or perhaps the author had missed some great stuff.

Two main ones: Mockito is, IMHO, much nicer than jMock. And Immutability is good, but 'final' is... complicated. I find it's often over used by people who don't know why they're using it.


Can you expand on the later point about final please?


tl;dr: final parameters != immutable and safety, and they look like they ought to.

A lot of people write "final" in front of every. single. declaration. And they do that because someone once told them that was good. But then you remember that Java is a language which all non-primitive types are passed by reference, so your 'final' is actually a final reference and not a const immutable object, like you might get in C.

If someone passes in a final FooBar to a method, and you mutate the FooBar during the method for any reason, then after the method is done the object remains mutated.

Just this week, that exact problem caused my team an entire day of headaches. Two methods were being called concurrently using Futures, passing the same object to each method. One method mutated the object slightly, the other relied on it having not been mutated. Hello race condition. I was so proud to have solved it, until I realized I'm the dolt who wrote the bug in the first place.

Silly, I know. But the point is that final makes you feel safe when you might not be.


> If someone passes in a final FooBar to a method, and you mutate the FooBar during the method for any reason, then after the method is done the object remains mutated.

Fair enough, but if FooBar is your class there's an easy fix for this - make FooBar immutable. If it's not, make an immutable wrapper object for it.

Very true that relying on untrue assumptions about the immutability of your data will cause hard-to-spot bugs, but the solution is then just to guarantee everything is immutable, and define that as an assumption that cannot be false if everyone on the team follows the pattern.

If somebody does break the pattern, then that, rather than the race condition down the line, is the real bug. The dev who wrote the mutable data class can just have that (re-)explained to them, so it doesn't happen again.


C const doesn't mean immutable either, and I suspect most Java programmers have no exposure to it in any case.

Honestly I don't think final ever makes things worse. I struggle to imagine someone who would misunderstand in the way you describe having any success in Java - references are a pretty fundamental part of the language.


i wish java had designed final to be semantically const just like C++ (but without the type level breakages that seems to happen in C++).


jMock isn't great, but Mockito makes it too hard to understand which method you haven't stubbed; I find EasyMock with its explicit replay() step much easier.


I rather like Moxie for mocking:

https://github.com/pobrelkey/moxiemocks


JMock at least blows up if you don't mock something. Powermock and Mockito will let it pass. It is a shame JMock's API is so wordy.


That's what I hate about JMock, lol.

You had better mock everything, and better put them in the exact order they will occur in, or your test fails.

Most JMock unit tests I see are essentially the exact same code as is being tested, written a second time in the unit test. So if I want to refactor or modify this code in any way, my unit tests break- even if functionally, my tests are doing exactly what their spec says.

With Mockito, I can say 'Hey, if anyone calls this method with parameters sort of like this, give them this response', and then focus on my unit tests actually testing the output for a given input.


Like I said, Easymock. Powermock has an Easymock API too if you need the mocking statics/object creation.


Eesh, let's agree to disagree. EasyMock has some advantages, but I find the readability of Mockito outweighs them.


Dependency Injection (frameworks) -1

Use constructors. This makes perfectly testable classes and is vastly simpler than encouraging more XML as code. Any proper dependency injection framework should work quite well with regular constructors.


Your comment is unclear. Are you encouraging people to NOT use DI frameworks, or using them only with constructor-based injection?


The latter. DI frameworks are a convenience item, they should probably not have a big effect on the way the code is written. You get most of the benefits of DI just from not new'ing up things within your classes.

The main advantage of keeping the constructors around is that you retain more flexibility in interacting with that bit of code.


I think people use DI just because Java constructor syntax is so incredibly verbose:

    public class MyClass {
      @Inject private String foo;
    }
versus

    public class MyClass {
      private String foo;

      @Inject public MyClass(String foo) {
        this.foo = foo;
      }
    }


Constructors have their problems. First: constructor calling is not readable because Java misses named parameters. It's fine when there are 2-3 dependencies, but not more. Second: circular dependency is not possible. So I prefer to use setter dependencies, as they don't have those problems.


Constructor calling is readable either with an IDE, or using distinctive types. If the constructor is unclear, it's a smell.

I'd also say that making circular dependencies not possible is a feature, not a bug. They go against everything we've learned about computing in the last 20 years. Entire languages do not have variables, or at least heavily discourage them, and the gains outweigh the costs.

Setter dependencies have other major disadvantages, like how easy they make creating partially initialized objects: Refactor something in one place, adding a parameter, and good luck making sure that the change is made everywhere else. A constructor guarantees fully initialized objects, and that's a great things.

Java pays for the mistakes of the early 2000s: The Java Bean pattern, and all the infrastructure around it, makes Java code be full of default constructors that force us into mutable objects and nullable fields.

If there is a defense for your argument for setter dependencies, is that we cannot count on any of the nice things that come with, say a Scala case class, because so much Java code out there is built with standards from a less enlightened era that using what would be better standards in any more modern language leads to inconsistencies, due to all the ancient code using Spring, Hibernate, Guava and EJB code that is hanging out there, and that would lead to inconsistencies for those trying to make Java actually use some of its new functional programming inspired features.


> First: constructor calling is not readable because Java misses named parameters. It's fine when there are 2-3 dependencies, but not more.

If you have more than 2-3 dependencies, it might be time to refactor things, as your class may be doing too many things.

> Second: circular dependency is not possible.

Circular dependencies are possible with constructor injection when using a DI framework (e.g., using a Provider in Guice [1], or the equivalent in Dagger).

[1] https://github.com/google/guice/wiki/CyclicDependencies


I agree on the first. I'm only advocating for keeping the constructor as the DI entry point. A DI framework can then be used for the convenience they provide in wiring things up at main.

Regarding the second: I think circular dependencies should be avoided whenever possible so I view the difficulty constructors create there as advantage rather than a problem.

https://en.wikipedia.org/wiki/Circular_dependency#Problems_o...


By using a DI framework to wire up constructors you tend to use the compile-time checking that your app is wired correctly. Which is unfortunate. You only find out when you try to run it.

Perhaps things being too big to wire together manually is a smell that the application is getting rather large.

There are also other patterns that can be used to make manual dependency injection less of a pain. I wrote about some of them here

http://benjiweber.co.uk/blog/2014/09/13/frameworkless-depend...


I'd rather inject some lazy somethingsomething-provider reference wrapper to break the occasional circular dependency than work with a bunch of nonfinal references that supposedly never change, because DI, but are otherwise indistinguishable from true working state.


Dependency injection is brilliant for testing. Prior to DI you often has to have two constructors, one for prod, one for testing. DI took that away.


I agreed with most of these suggestions. I'm not sure the suggestion to use a struct pattern is worth the lack of JavaBeans support in argle support libraries. You can always use final properties and only provide getters.

I think asserting that Fluent interfaces are 'more readable' or better is largely a matter of opinion.


Some good suggestions in here and some very very bad ones. For example, using Optional as a member type, tuples etc.


this details a good amount of the problems with optional, but yet why it will still be used despite it: https://developer.atlassian.com/blog/2015/08/optional-broken...


>Java 8 has a nice stream and lambda syntax. You could write code like this:

  final List<String> filtered = list.stream()
    .filter(s -> s.startsWith("s"))
    .map(s -> s.toUpperCase())
    .collect(Collectors.toList());
>Instead of this:

  final List<String> filtered = new ArrayList<>();
  for (String str : list) {
    if (str.startsWith("s") {
      filtered.add(str.toUpperCase());
    }
  }
>This allows you to write more fluent code, which is more readable.

I don't agree. The second snipped is far more readable. This seems like an effort to use lambdas just to be using lambdas.

Not only that, but the non-lambda version is far easier to maintain. When you get exceptions in code that has the form

  this().that().theOther()
it's generally not obvious where the problem is.


A matter of personal taste, but I greatly prefer the lambda style (though I wish the example had the .stream() on the following line).

I have been coding Java (and C-style) languages for a really long time. And, I still have some cognitive delay when traversing multiple indented scopes. Not a long delay, but long enough to be slightly annoying.

With the lambda style, I can quickly glance down the text column to see what's going on. Stream -> Map -> Filter -> Collect.

After using lambdas enough, one starts to subconsciously cull the stream() and collect() calls. So, when I look at it, I really see Map -> Filter.

But what really, really annoys me is that exception handling can't be applied to the whole stream processing statement. This leads to code that looks like:

    collection
            .stream()
            .map(o -> {
                try {
                    return o.oToC();
                } catch(Exception e) {
                    // handle
                }
                return new C();
             })
            .reduce((c1, c2) -> {
                try {
                    return c1.combine(c2);
                } catch(Exception e) {
                    // handle
                }
                return c1;
             });
For that, I have had to write a bunch of helper functions that wrap and throw the exceptions.


I note that it's not safe to pass Java 8 streams around as streams can be closed when invoking terminal operations. If you pass a stream to a method and do not know whether the method is going to close the stream, it's dangerous to reuse it after the method return.


Well, once a Stream has been consumed, you can't use it again. We have a rule of thumb in my team that our APIs should not consume or return Stream or Optional.


I find lauding use of Optional over null for return values, but eschewing checked exceptions somewhat inconsistent. The problem with null is it can be returned anywhere, from any function. It is difficult to generate compile time errors for if they go unhandled. But unchecked exceptions are great because you don’t have to then think about them. hmmm.

Addendum: I’m also of the opinion that trying to write java code without an IDE is highly inefficient. With an IDE, you can locate all the throws you’re not taking care of quickly, and usually quickly deal with them to get things to compile. Yeah, it’s a bit of housekeeping overhead, but once they are dealt with, they are dealt with, even if it is just passing them upstream.


I've worked on two Spring Boot projects so far and written somewhere between zero and no XML.


Guava is on github now. Might want to change the link.


I've been using spring loaded instead of jrebel and it works pretty well and is free.

One thing I'm surprised he didn't mention is exception handling. Namely the growing acceptance that checked exceptions are dumb. I make a point that except for a few rare circumstanes, my code should never have a throws clause. I always created subclasses of RuntimeException (or Spring's NestedRuntimeException) and use them exclusively. Any libs that throw checked exceptions get either handled or rethrown with a custom RuntimeException.


As a Java Dev of 15 years, through my own experience, almost all of these points I have discovered through hard fought bugs and trying to find a way to reduce the causes of them in the future.

Final by default is the biggest, bc it removes some of the most basic concurrency errors implicitly. Awesome post. It also is pointing out things that in some other languages (e.g. Python) are implicitly impossible to achieve, and others which some new languages (e.g. Rust) have built in from the beginning, like never use null.

Well done.


What web frameworks are you guys using in the Java 8 world that lets you leverage newer language features?

Is it still Spring ? Are you guys doing things like Socket.io , etc.

And is Hibernate the preferred orm ? Confession: I'm an ex Java programmer, who have been working in rails and python for past several years...so am fairly out of date. I have kept up with things like Dropwizard...but have not seen many other startups do Java development.


Spring is on Java 7 for the 4.x series.

Spring 5 will take Java 8 as the baseline.


Nice! Seeing "enterprise" java code anyways makes my blood boil, and I keep reminding myself that it doesn't have to be that ugly.


The only way it seems you can be effective with Java is with an IDE to do most of the heavy lifting. What would be better is if Java shipped with more focused command-line tools and better defaults that allow me to productive immediately without the need to learn something as hefty as IntelliJ / Eclipse. This could lessen the barrier of entry to Java and widen community adoption.


The command-line tools are fine. And Java is the most adopted language in existence.

The problem with writing Java without an IDE isn't one of tooling, it's that the language is so very verbose. They're working on that with lambdas and generics inference, but there's a limit to what you can do and remain backwards compatible.


Or you could just use modern JVM languages like Clojure.


I like Clojure, but anyway to make it start faster in a scripting context? I wrote the same script in Clojure and Kotlin, and the Kotlin one loads so much faster.


There's Planck for OS X https://github.com/mfikes/planck

It uses JavaScriptCore and starts practically instantly. There's some work being done to port it to Linux/Windows as well.

Here's an example:

cat foo.cljs

#!/usr/local/bin/planck

(println "hello world: clojurescript -> planck -> as shell script")

./foo.cljs

hello world: clojurescript -> planck -> as shell script

Planck can be installed using homebrew now as well.

Another promising option is Pixie https://github.com/pixie-lang/pixie


Cheers mate :)


Lisp? Lisp syntax makes less sense than lambda and stream which have ruined Java.


What would you use instead of an IDE? Learning Intellij is a lot easier than learning Vim or Emacs.


Nice compendium. I don't agree with everything, but I doubt you can get an Java devs to agree on everything.


For web framework I would also suggest Dropwizard. Its simple easy to use and robust.


If you really want to describe modern Java, you should probably mention RxJava and TestNG.


TestNG may have been considered a "modern" alternative years ago, but today jUnit4 has caught up with most (if not all) of testNG's features.


Nothing on findbugs, checkstyle, EOL and CVEs?

log4j: now log4j2

jOOQ => $, JPA, MyBatis


'Formatting is so much less important than most programmers make it out to be. Does consistency show that you care about your craft and does it help others read? Absolutely. But let's not waste a day adding spaces to if blocks so that it "matches".'

I do agree that it's less important, but it's so easy to do that there is no excuse for not doing it or giving out such rubbish advice. Anyone that wastes a day on formatting is doing it wrong. The problem with advice like this is that people take it to the extreme and ignore formatting altogether. That leads to someone being frustrated and formatting all the files automatically (as should be done anyway) which then leads to possible conflict and crappy diffs. Instead, you could have had professional programmers work on these. In an industry that's touting how code readability is so important (and it is), this advice is toxic. We're finally getting people to realize that readability is the most important part for most code because it is. Honestly, formatting is important in this inconsequential reply, in essays, in everything we write except short chat messages. Imsurenoonewouldliketoreadsentenceslikethis just like no one wants to read obfuscated, unformatted, crappy code. So yeah, I disagree strongly because formatting is important, get one style, get proper tools to automate it, and then you don't have to spend a day putting in spaces (which is ridiculous).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: