{"id":13399554,"url":"https://github.com/cxxr/better-java","last_synced_at":"2025-05-14T11:08:51.405Z","repository":{"id":16715960,"uuid":"19472884","full_name":"cxxr/better-java","owner":"cxxr","description":"Resources for writing modern Java","archived":false,"fork":false,"pushed_at":"2023-05-04T06:20:46.000Z","size":123,"stargazers_count":5792,"open_issues_count":25,"forks_count":728,"subscribers_count":347,"default_branch":"master","last_synced_at":"2025-04-11T22:59:03.939Z","etag":null,"topics":["guide","java"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cxxr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-05-05T22:10:53.000Z","updated_at":"2025-04-08T15:15:45.000Z","dependencies_parsed_at":"2024-01-13T17:55:52.353Z","dependency_job_id":"d120614b-e91e-424b-9874-e3a6d9b07764","html_url":"https://github.com/cxxr/better-java","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxxr%2Fbetter-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxxr%2Fbetter-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxxr%2Fbetter-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cxxr%2Fbetter-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cxxr","download_url":"https://codeload.github.com/cxxr/better-java/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254129482,"owners_count":22019628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["guide","java"],"created_at":"2024-07-30T19:00:39.388Z","updated_at":"2025-05-14T11:08:51.383Z","avatar_url":"https://github.com/cxxr.png","language":null,"readme":"*Note*: I'm working on version 2 of this guide and I need your help! Please use [this form to give me feedback](https://goo.gl/forms/yoWihX9ZjPI9x24o1) on what you think should go in the next version. Thanks!\n\n\n# Better Java\n\nJava is one of the most popular programming languages around, but no one seems\nto enjoy using it. Well, Java is actually an alright programming language, and\nsince Java 8 came out recently, I decided to compile a list of libraries, \npractices, and tools to make using Java better. \"Better\" is subjective, so I\nwould recommend taking the parts that speak to you and use them, rather than\ntrying to use all of them at once. Feel free to submit pull requests \nsuggesting additions.\n\nThis article was originally posted on \n[my blog](https://www.seancassidy.me/better-java.html).\n\nRead this in other languages: [English](README.md), [简体中文](README.zh-cn.md)\n\n## Table Of Contents\n\n* [Style](#style)\n  * [Structs](#structs)\n    * [The Builder Pattern](#the-builder-pattern)\n    * [Immutable Object Generation](#immutable-object-generation)\n  * [Exceptions](#exceptions)\n  * [Dependency injection](#dependency-injection)\n  * [Avoid Nulls](#avoid-nulls)\n  * [Immutable-by-default](#immutable-by-default)\n  * [Avoid lots of Util classes](#avoid-lots-of-util-classes)\n  * [Formatting](#formatting)\n    * [Javadoc](#javadoc)\n  * [Streams](#streams)\n* [Deploying](#deploying)\n  * [Frameworks](#frameworks)\n  * [Maven](#maven)\n    * [Dependency Convergence](#dependency-convergence)\n  * [Continuous Integration](#continuous-integration)\n  * [Maven repository](#maven-repository)\n  * [Configuration management](#configuration-management)\n* [Libraries](#libraries)\n  * [Missing Features](#missing-features)\n    * [Apache Commons](#apache-commons)\n    * [Guava](#guava)\n    * [Gson](#gson)\n    * [Java Tuples](#java-tuples)\n    * [Javaslang](#javaslang)\n    * [Joda-Time](#joda-time)\n    * [Lombok](#lombok)\n    * [Play framework](#play-framework)\n    * [SLF4J](#slf4j)\n    * [jOOQ](#jooq)\n  * [Testing](#testing)\n    * [jUnit 4](#junit-4)\n    * [jMock](#jmock)\n    * [AssertJ](#assertj)\n* [Tools](#tools)\n  * [IntelliJ IDEA](#intellij-idea)\n    * [Chronon](#chronon)\n  * [JRebel](#jrebel)\n  * [The Checker Framework](#the-checker-framework)\n  * [Code Quality](#code-quality)\n  * [Eclipse Memory Analyzer](#eclipse-memory-analyzer)\n* [Resources](#resources)\n  * [Books](#books)\n  * [Podcasts](#podcasts)\n  * [Videos](#videos)\n\n## Style\n\nTraditionally, Java was programmed in a very verbose enterprise JavaBean style.\nThe new style is much cleaner, more correct, and easier on the eyes.\n\n### Structs\n\nOne of the simplest things we as programmers do is pass around data. The\ntraditional way to do this is to define a JavaBean:\n\n```java\npublic class DataHolder {\n    private String data;\n\n    public DataHolder() {\n    }\n\n    public void setData(String data) {\n        this.data = data;\n    }\n\n    public String getData() {\n        return this.data;\n    }\n}\n```\n\nThis is verbose and wasteful. Even if your IDE automatically generated this\ncode, it's a waste. So, [don't do this][dontbean].\n\nInstead, I prefer the C struct style of writing classes that merely hold data:\n\n```java\npublic class DataHolder {\n    public final String data;\n\n    public DataHolder(String data) {\n        this.data = data;\n    }\n}\n```\n\nThis is a reduction in number of lines of code by a half. Further, this class\nis immutable unless you extend it, so we can reason about it easier as we know\nthat it can't be changed.\n\nIf you're storing objects like Map or List that can be modified easily, you\nshould instead use ImmutableMap or ImmutableList, which is discussed in the \nsection about immutability.\n\n#### The Builder Pattern\n\nIf you have a rather complicated object that you want to build a struct for,\nconsider the Builder pattern.\n\nYou make a static inner class which will construct your object. It uses\nmutable state, but as soon as you call build, it will emit an immutable\nobject.\n\nImagine we had a more complicated *DataHolder*. The builder for it might look\nlike:\n\n```java\npublic class ComplicatedDataHolder {\n    public final String data;\n    public final int num;\n    // lots more fields and a constructor\n\n    public static class Builder {\n        private String data;\n        private int num;\n        \n        public Builder data(String data) {\n            this.data = data;\n            return this;\n        }\n\n        public Builder num(int num) {\n            this.num = num;\n            return this;\n        }\n\n        public ComplicatedDataHolder build() {\n            return new ComplicatedDataHolder(data, num); // etc\n        }  \n    }\n}\n```\n\nThen to use it:\n\n```java\nfinal ComplicatedDataHolder cdh = new ComplicatedDataHolder.Builder()\n    .data(\"set this\")\n    .num(523)\n    .build();\n```\n\nThere are [better examples of Builders elsewhere][builderex] but this should\ngive you a taste for what it's like. This ends up with a lot of the boilerplate\nwe were trying to avoid, but it gets you immutable objects and a very fluent\ninterface. \n\nInstead of creating builder objects by hand, consider using one of the many \nlibraries which can help you generate builders.\n\n#### Immutable Object Generation\n\nIf you create many immutable objects by hand, consider using the annotation \nprocessor to generate them from interfaces automatically. This minimizes \nboilerplate code, reduces probability of bugs and promotes immutability. See\nthis [presentation](https://docs.google.com/presentation/d/14u_h-lMn7f1rXE1nDiLX0azS3IkgjGl5uxp5jGJ75RE/edit#slide=id.g2a5e9c4a8_00)\nfor an interesting discussion of some of the problems with normal Java coding\npatterns.\n\nSome great code generation libraries are [immutables](https://github.com/immutables/immutables), Google's \n[auto-value](https://github.com/google/auto/tree/master/value) and \n[Lombok][lombok].\n\n### Exceptions\n\n[Checked exceptions][checkedex] should be used with caution, if at all. They \nforce your users to add many try/catch blocks and wrap your exceptions in their \nown. Better is to make your exceptions extend RuntimeException instead. This \nallows your users to handle your exceptions in the way they would like, rather \nthan forcing them to handle/declare that it throws every time, which pollutes \nthe code.\n\nOne nifty trick is to put RuntimeExceptions in your method's throws declaration.\nThis has no effect on the compiler, but will inform your users via documentation\nthat these exceptions can be thrown.\n\n### Dependency injection\n\nThis is more of a software engineering section than a Java section, but one of\nthe best ways to write testable software is to use [dependency injection][di]\n(DI). Because Java strongly encourages OO design, to make testable software,\nyou need to use DI.\n\nIn Java, this is typically done with the [Spring Framework][spring]. It has a\neither code-based wiring or XML configuration-based wiring. If you use the XML \nconfiguration, it's important that you [don't overuse Spring][springso] because\nof its XML-based configuration format.  There should be absolutely no logic or\ncontrol structures in XML. It should only inject dependencies.\n\nGood alternatives to using Spring is Google and Square's [Dagger][dagger]\nlibrary or Google's [Guice][guice]. They don't use Spring's XML \nconfiguration file format, and instead they put the injection logic in\nannotations and in code.\n\n### Avoid Nulls\n\nTry to avoid using nulls when you can. Do not return null collections when you\nshould have instead returned an empty collection. If you're going to use null, \nconsider the [@Nullable][nullable] annotation. [IntelliJ IDEA][intellij] has \nbuilt-in support for the @Nullable annotation.\n\nRead more about why not to use nulls in\n[The worst mistake of computer science][the-worst-mistake-of-computer-science].\n\nIf you're using [Java 8][java8], you can use the excellent new \n[Optional][optional] type. If a value may or may not be present, wrap it in\nan *Optional* class like this:\n\n```java\npublic class FooWidget {\n    private final String data;\n    private final Optional\u003cBar\u003e bar;\n\n    public FooWidget(String data) {\n        this(data, Optional.empty());\n    }\n\n    public FooWidget(String data, Optional\u003cBar\u003e bar) {\n        this.data = data;\n        this.bar = bar;\n    }\n\n    public Optional\u003cBar\u003e getBar() {\n        return bar;\n    }\n}\n```\n\nSo now it's clear that *data* will never be null, but *bar* may or may not be\npresent. *Optional* has methods like *isPresent*, which may make it feel like\nnot a lot is different from just checking *null*. But it allows you to write\nstatements like:\n\n```java\nfinal Optional\u003cFooWidget\u003e fooWidget = maybeGetFooWidget();\nfinal Baz baz = fooWidget.flatMap(FooWidget::getBar)\n                         .flatMap(BarWidget::getBaz)\n                         .orElse(defaultBaz);\n```\n\nWhich is much better than chained if null checks. The only downside of using\nOptional is that the standard library doesn't have good Optional support, so\ndealing with nulls is still required there.\n\n### Immutable-by-default\n\nUnless you have a good reason to make them otherwise, variables, classes, and\ncollections should be immutable.\n\nVariables can be made immutable with *final*:\n\n```java\nfinal FooWidget fooWidget;\nif (condition()) {\n    fooWidget = getWidget();\n} else {\n    try {\n        fooWidget = cachedFooWidget.get();\n    } catch (CachingException e) {\n        log.error(\"Couldn't get cached value\", e);\n        throw e;\n    }\n}\n// fooWidget is guaranteed to be set here\n```\n\nNow you can be sure that fooWidget won't be accidentally reassigned. The *final*\nkeyword works with if/else blocks and with try/catch blocks. Of course, if the\n*fooWidget* itself isn't immutable you could easily mutate it.\n\nCollections should, whenever possible, use the Guava\n[ImmutableMap][immutablemap], [ImmutableList][immutablelist], or\n[ImmutableSet][immutableset] classes. These have builders so that you can build\nthem up dynamically and then mark them immutable by calling the build method.\n\nClasses should be made immutable by declaring fields immutable (via *final*)\nand by using immutable collections. Optionally, you can make the class itself \n*final* so that it can't be extended and made mutable.\n\n### Avoid lots of Util classes\n\nBe careful if you find yourself adding a lot of methods to a Util class.\n\n```java\npublic class MiscUtil {\n    public static String frobnicateString(String base, int times) {\n        // ... etc\n    }\n\n    public static void throwIfCondition(boolean condition, String msg) {\n        // ... etc\n    }\n}\n```\n\nThese classes, at first, seem attractive because the methods that go in them\ndon't really belong in any one place. So you throw them all in here in the\nname of code reuse.\n\nThe cure is worse than the disease. Put these classes where they belong and\nrefactor aggressively. Don't name classes, packages, or libraries anything\ntoo generic, such as \"MiscUtils\" or \"ExtrasLibrary\". This encourages dumping \nunrelated code there.\n\n### Formatting\n\nFormatting is so much less important than most programmers make it out to be.\nDoes consistency show that you care about your craft and does it help others\nread? Absolutely. But let's not waste a day adding spaces to if blocks so that\nit \"matches\".\n\nIf you absolutely need a code formatting guide, I highly recommend\n[Google's Java Style][googlestyle] guide. The best part of that guide is the\n[Programming Practices][googlepractices] section. Definitely worth a read.\n\n#### Javadoc\n\nDocumenting your user facing code is important. And this means \n[using examples][javadocex] and using sensible descriptions of variables,\nmethods, and classes.\n\nThe corollary of this is to not document what doesn't need documenting. If you\ndon't have anything to say about what an argument is, or if it's obvious,\ndon't document it. Boilerplate documentation is worse than no documentation at\nall, as it tricks your users into thinking that there is documentation.\n\n### Streams\n\n[Java 8][java8] has a nice [stream][javastream] and lambda syntax. You could\nwrite code like this:\n\n```java\nfinal List\u003cString\u003e filtered = list.stream()\n    .filter(s -\u003e s.startsWith(\"s\"))\n    .map(s -\u003e s.toUpperCase())\n    .collect(Collectors.toList());\n```\n\nInstead of this:\n\n```java\nfinal List\u003cString\u003e filtered = new ArrayList\u003c\u003e();\nfor (String str : list) {\n    if (str.startsWith(\"s\") {\n        filtered.add(str.toUpperCase());\n    }\n}\n```\n\nThis allows you to write more fluent code, which is more readable.\n\n## Deploying\n\nDeploying Java properly can be a bit tricky. There are two main ways to deploy\nJava nowadays: use a framework or use a home grown solution that is more\nflexible.\n\n### Frameworks\n\nBecause deploying Java isn't easy, frameworks have been made which can help.\nTwo of the best are [Dropwizard][dropwizard] and [Spring Boot][springboot].\nThe [Play framework][play] can also be considered one of these deployment \nframeworks as well.\n\nAll of them try to lower the barrier to getting your code out the door. \nThey're especially helpful if you're new to Java or if you need to get things\ndone fast. Single JAR deployments are just easier than complicated WAR or EAR\ndeployments.\n\nHowever, they can be somewhat inflexible and are rather opinionated, so if\nyour project doesn't fit with the choices the developers of your framework\nmade, you'll have to migrate to a more hand-rolled configuration.\n\n### Maven\n\n**Good alternative**: [Gradle][gradle].\n\nMaven is still the standard tool to build, package, and run your tests. There\nare alternatives, like Gradle, but they don't have the same adoption that Maven \nhas. If you're new to Maven, you should start with\n[Maven by Example][mavenexample].\n\nI like to have a root POM with all of the external dependencies you want to\nuse. It will look something [like this][rootpom]. This root POM has only one\nexternal dependency, but if your product is big enough, you'll have dozens.\nYour root POM should be a project on its own: in version control and released\nlike any other Java project.\n\nIf you think that tagging your root POM for every external dependency change\nis too much, you haven't wasted a week tracking down cross project dependency\nerrors.\n\nAll of your Maven projects will include your root POM and all of its version\ninformation.  This way, you get your company's selected version of each\nexternal dependency, and all of the correct Maven plugins. If you need to pull\nin external dependencies, it works just like this:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.third.party\u003c/groupId\u003e\n        \u003cartifactId\u003esome-artifact\u003c/artifactId\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\nIf you want internal dependencies, that should be managed by each individual\nproject's **\u003cdependencyManagement\u003e** section. Otherwise it would be difficult\nto keep the root POM version number sane.\n\n#### Dependency Convergence\n\nOne of the best parts about Java is the massive amount of third party\nlibraries which do everything. Essentially every API or toolkit has a Java SDK\nand it's easy to pull it in with Maven.\n\nAnd those Java libraries themselves depend on specific versions of other\nlibraries. If you pull in enough libraries, you'll get version conflicts, that\nis, something like this:\n\n    Foo library depends on Bar library v1.0\n    Widget library depends on Bar library v0.9\n\nWhich version will get pulled into your project?\n\nWith the [Maven dependency convergence plugin][depconverge], the build will \nerror if your dependencies don't use the same version. Then, you have two\noptions for solving the conflict:\n\n1. Explicitly pick a version for Bar in your *dependencyManagement* section\n2. Exclude Bar from either Foo or Widget\n\nThe choice of which to choose depends on your situation: if you want to track\none project's version, then exclude makes sense. On the other hand, if you\nwant to be explicit about it, you can pick a version, although you'll need to\nupdate it when you update the other dependencies.\n\n### Continuous Integration\n\nObviously you need some kind of continuous integration server which is going\nto continuously build your SNAPSHOT versions and tag builds based on git tags.\n\n[Jenkins][jenkins] and [Travis-CI][travis] are natural choices.\n\nCode coverage is useful, and [Cobertura][cobertura] has \n[a good Maven plugin][coberturamaven] and CI support. There are other code\ncoverage tools for Java, but I've used Cobertura.\n\n### Maven repository\n\nYou need a place to put your JARs, WARs, and EARs that you make, so you'll\nneed a repository.\n\nCommon choices are [Artifactory][artifactory] and [Nexus][nexus]. Both work,\nand have their own [pros and cons][mavenrepo].\n\nYou should have your own Artifactory/Nexus installation and \n[mirror your dependencies][artifactorymirror] onto it. This will stop your\nbuild from breaking because some upstream Maven repository went down.\n\n### Configuration management\n\nSo now you've got your code compiled, your repository set up, and you need to\nget your code out in your development environment and eventually push it to\nproduction. Don't skimp here, because automating this will pay dividends for a\nlong time.\n\n[Chef][chef], [Puppet][puppet], and [Ansible][ansible] are typical choices.\nI've written an alternative called [Squadron][squadron], which I, of course,\nthink you should check out because it's easier to get right than the\nalternatives.\n\nRegardless of what tool you choose, don't forget to automate your deployments.\n\n## Libraries\n\nProbably the best feature about Java is the extensive amount of libraries it \nhas. This is a small collection of libraries that are likely to be applicable\nto the largest group of people.\n\n### Missing Features\n\nJava's standard library, once an amazing step forward, now looks like it's\nmissing several key features.\n\n#### Apache Commons\n\n[The Apache Commons project][apachecommons] has a bunch of useful libraries.\n\n**Commons Codec** has many useful encoding/decoding methods for Base64 and hex\nstrings. Don't waste your time rewriting those.\n\n**Commons Lang** is the go-to library for String manipulation and creation, \n    character sets, and a bunch of miscellaneous utility methods.\n\n**Commons IO** has all the File related methods you could ever want. It has \n[FileUtils.copyDirectory][copydir], [FileUtils.writeStringToFile][writestring],\n[IOUtils.readLines][readlines] and much more.\n\n#### Guava\n\n[Guava][guava] is Google's excellent here's-what-Java-is-missing library. It's\nalmost hard to distill everything that I like about this library, but I'm\ngoing to try.\n\n**Cache** is a simple way to get an in-memory cache that can be used to cache\nnetwork access, disk access, memoize functions, or anything really. Just\nimplement a [CacheBuilder][cachebuilder] which tells Guava how to build your\ncache and you're all set!\n\n**Immutable** collections. There's a bunch of these:\n[ImmutableMap][immutablemap], [ImmutableList][immutablelist], or even\n[ImmutableSortedMultiSet][immutablesorted] if that's your style.\n\nI also like writing mutable collections the Guava way:\n\n```java\n// Instead of\nfinal Map\u003cString, Widget\u003e map = new HashMap\u003c\u003e();\n\n// You can use\nfinal Map\u003cString, Widget\u003e map = Maps.newHashMap();\n```\n\nThere are static classes for [Lists][lists], [Maps][maps], [Sets][sets] and\nmore. They're cleaner and easier to read.\n\nIf you're stuck with Java 6 or 7, you can use the [Collections2][collections2]\nclass, which has methods like filter and transform. They allow you to write\nfluent code without [Java 8][java8]'s stream support.\n\n\nGuava has simple things too, like a **Joiner** that joins strings on \nseparators and a [class to handle interrupts][uninterrupt] by ignoring them.\n\n#### Gson\n\nGoogle's [Gson][gson] library is a simple and fast JSON parsing library. It\nworks like this:\n\n```java\nfinal Gson gson = new Gson();\nfinal String json = gson.toJson(fooWidget);\n\nfinal FooWidget newFooWidget = gson.fromJson(json, FooWidget.class);\n```\n\nIt's really easy and a pleasure to work with. The [Gson user guide][gsonguide]\nhas many more examples.\n\n#### Java Tuples\n\nOne of my on going annoyances with Java is that it doesn't have tuples built\ninto the standard library. Luckily, the [Java tuples][javatuples] project fixes\nthat.\n\nIt's simple to use and works great:\n\n```java\nPair\u003cString, Integer\u003e func(String input) {\n    // something...\n    return Pair.with(stringResult, intResult);\n}\n```\n\n#### Javaslang\n\n[Javaslang][javaslang] is a functional library, designed to add missing features\nthat should have been part of Java 8. Some of these features are\n\n* an all-new functional collection library\n* tightly integrated tuples\n* pattern matching\n* throughout thread-safety because of immutability\n* eager and lazy data types\n* null-safety with the help of Option\n* better exception handling with the help of Try\n\nThere are several Java libraries which depend on the original Java collections.\nThese are restricted to stay compatible to classes which were created with an\nobject-oriented focus and designed to be mutable. The Javaslang collections for\nJava are a completely new take, inspired by Haskell, Clojure and Scala. They are\ncreated with a functional focus and follow an immutable design.\n\nCode like this is automatically thread safe and try-catch free:\n\n```java\n// Success/Failure containing the result/exception\npublic static Try\u003cUser\u003e getUser(int userId) {\n    return Try.of(() -\u003e DB.findUser(userId))\n        .recover(x -\u003e Match.of(x)\n            .whenType(RemoteException.class).then(e -\u003e ...)\n            .whenType(SQLException.class).then(e -\u003e ...));\n}\n\n// Thread-safe, reusable collections\npublic static List\u003cString\u003e sayByeBye() {\n    return List.of(\"bye, \"bye\", \"collect\", \"mania\")\n               .map(String::toUpperCase)\n               .intersperse(\" \");\n}\n```\n\n#### Joda-Time\n\n[Joda-Time][joda] is easily the best time library I've ever used. Simple,\nstraightforward, easy to test. What else can you ask for? \n\nYou only need this if you're not yet on Java 8, as that has its own new \n[time][java8datetime] library that doesn't suck.\n\n#### Lombok\n\n[Lombok][lombok] is an interesting library. Through annotations, it allows you\nto reduce the boilerplate that Java suffers from so badly.\n\nWant setters and getters for your class variables? Simple:\n\n```java\npublic class Foo {\n    @Getter @Setter private int var;\n}\n```\n\nNow you can do this:\n\n```java\nfinal Foo foo = new Foo();\nfoo.setVar(5);\n```\n\nAnd there's [so much more][lombokguide]. I haven't used Lombok in production\nyet, but I can't wait to.\n\n#### Play framework\n\n**Good alternatives**: [Jersey][jersey] or [Spark][spark]\n\nThere are two main camps for doing RESTful web services in Java: \n[JAX-RS][jaxrs] and everything else.\n\nJAX-RS is the traditional way. You combine annotations with interfaces and\nimplementations to form the web service using something like [Jersey][jersey].\nWhat's nice about this is you can easily make clients out of just the \ninterface class.\n\nThe [Play framework][play] is a radically different take on web services on\nthe JVM: you have a routes file and then you write the classes referenced in\nthose routes. It's actually an [entire MVC framework][playdoc], but you can\neasily use it for just REST web services.\n\nIt's available for both Java and Scala. It suffers slightly from being \nScala-first, but it's still good to use in Java.\n\nIf you're used to micro-frameworks like Flask in Python, [Spark][spark] will\nbe very familiar. It works especially well with Java 8.\n\n#### SLF4J\n\nThere are a lot of Java logging solutions out there. My favorite is\n[SLF4J][slf4j] because it's extremely pluggable and can combine logs from many\ndifferent logging frameworks at the same time. Have a weird project that uses\njava.util.logging, JCL, and log4j? SLF4J is for you.\n\nThe [two-page manual][slf4jmanual] is pretty much all you'll need to get\nstarted.\n\n#### jOOQ\n\nI dislike heavy ORM frameworks because I like SQL. So I wrote a lot of\n[JDBC templates][jdbc] and it was sort of hard to maintain. [jOOQ][jooq] is a\nmuch better solution.\n\nIt lets you write SQL in Java in a type safe way:\n\n```java\n// Typesafely execute the SQL statement directly with jOOQ\nResult\u003cRecord3\u003cString, String, String\u003e\u003e result = \ncreate.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)\n    .from(BOOK)\n    .join(AUTHOR)\n    .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID))\n    .where(BOOK.PUBLISHED_IN.equal(1948))\n    .fetch();\n```\n\nUsing this and the [DAO][dao] pattern, you can make database access a breeze.\n\n### Testing\n\nTesting is critical to your software. These packages help make it easier.\n\n#### jUnit 4\n\n**Good alternative**: [TestNG][testng].\n\n[jUnit][junit] needs no introduction. It's the standard tool for unit testing\nin Java.\n\nBut you're probably not using jUnit to its full potential. jUnit supports\n[parametrized tests][junitparam], [rules][junitrules] to stop you from writing\nso much boilerplate, [theories][junittheories] to randomly test certain code,\nand [assumptions][junitassume].\n\n#### jMock\n\nIf you've done your dependency injection, this is where it pays off: mocking\nout code which has side effects (like talking to a REST server) and still\nasserting behavior of code that calls it.\n\n[jMock][jmock] is the standard mocking tool for Java. It looks like this:\n\n```java\npublic class FooWidgetTest {\n    private Mockery context = new Mockery();\n\n    @Test\n    public void basicTest() {\n        final FooWidgetDependency dep = context.mock(FooWidgetDependency.class);\n        \n        context.checking(new Expectations() {{\n            oneOf(dep).call(with(any(String.class)));\n            atLeast(0).of(dep).optionalCall();\n        }});\n\n        final FooWidget foo = new FooWidget(dep);\n\n        Assert.assertTrue(foo.doThing());\n        context.assertIsSatisfied();\n    }\n}\n```\n\nThis sets up a *FooWidgetDependency* via jMock and then adds expectations. We\nexpect that *dep*'s *call* method will be called once with some String and that\n*dep*'s *optionalCall* method will be called zero or more times.\n\nIf you have to set up the same dependency over and over, you should probably\nput that in a [test fixture][junitfixture] and put *assertIsSatisfied* in an\n*@After* fixture.\n\n#### AssertJ\n\nDo you ever do this with jUnit?\n\n```java\nfinal List\u003cString\u003e result = some.testMethod();\nassertEquals(4, result.size());\nassertTrue(result.contains(\"some result\"));\nassertTrue(result.contains(\"some other result\"));\nassertFalse(result.contains(\"shouldn't be here\"));\n```\n\nThis is just annoying boilerplate. [AssertJ][assertj] solves this. You can\ntransform the same code into this:\n\n```java\nassertThat(some.testMethod()).hasSize(4)\n                             .contains(\"some result\", \"some other result\")\n                             .doesNotContain(\"shouldn't be here\");\n```\n\nThis fluent interface makes your tests more readable. What more could you want?\n\n## Tools\n\n### IntelliJ IDEA\n\n**Good alternatives**: [Eclipse][eclipse] and [Netbeans][netbeans]\n\nThe best Java IDE is [IntelliJ IDEA][intellij]. It has a ton of awesome\nfeatures, and is really the main thing that makes the verbosity of Java\nbareable. Autocomplete is great, \n[the inspections are top notch][intellijexample], and the refactoring\ntools are really helpful.\n\nThe free community edition is good enough for me, but there are loads of great\nfeatures in the Ultimate edition like database tools, Spring Framework support\nand Chronon.\n\n#### Chronon\n\nOne of my favorite features of GDB 7 was the ability to travel back in time\nwhen debugging. This is possible with the [Chronon IntelliJ plugin][chronon]\nwhen you get the Ultimate edition.\n\nYou get variable history, step backwards, method history and more. It's a\nlittle strange to use the first time, but it can help debug some really\nintricate bugs, Heisenbugs and the like.\n\n### JRebel\n\n**Good alternative**: [DCEVM](https://github.com/dcevm/dcevm)\n\nContinuous integration is often a goal of software-as-a-service products. What\nif you didn't even need to wait for the build to finish to see code changes\nlive?\n\nThat's what [JRebel][jrebel] does. Once you hook up your server to your JRebel\nclient, you can see changes on your server instantly. It's a huge time savings\nwhen you want to experiment quickly.\n\n### The Checker Framework\n\nJava's type system is pretty weak. It doesn't differentiate between Strings\nand Strings that are actually regular expressions, nor does it do any\n[taint checking][taint]. However, [the Checker Framework][checker]\ndoes this and more.\n\nIt uses annotations like *@Nullable* to check types. You can even define \n[your own annotations][customchecker] to make the static analysis done even\nmore powerful.\n\n### Code Quality\n\nEven when following best practices, even the best developer will make mistakes.\nThere are a number of tools out there that you can use to validate your Java\ncode to detect problems in your code. Below is a small selection of some of the\nmost popular tools. Many of these integrate with popular IDE's such as Eclipse\nor IntelliJ enabling you to spot mistakes in your code sooner.\n\n* **[Checkstyle](http://checkstyle.sourceforge.net/ \"Checkstyle\")**: A static\ncode analyzer whose primary focus is to ensure that your code adheres to a\ncoding standard. Rules are defined in an XML file that can be checked into\nsource control alongside your code.\n* **[FindBugs](http://findbugs.sourceforge.net/ \"FindBugs\")**: Aims to spot code\nthat can result in bugs/errors. Runs as a standalone process but has good\nintegration into modern IDE's and build tools.\n* **[PMD](https://pmd.github.io/ \"PMD\")**: Similar to FindBugs, PMD aims to spot\ncommon mistakes \u0026 possible tidy-ups in your code. What rules are run against\nyour code can be controlled via an XML file you can commit alongside your code.\n* **[SonarQube](http://www.sonarqube.org/ \"SonarQube\")**: Unlike the previous\ntools that run locally, SonarQube runs on a server that you submit your code to\nfor analysis. It provides a web GUI where you are able to gain a wealth of\ninformation about your code such as bad practices, potential bugs, percentage\ntest coverage and the level of\n[technical debt](https://en.wikipedia.org/wiki/Technical_debt \"Technical Debt on Wikipedia\")\nin your code.\n\nAs well as using these tools during development, it's often a good idea to also\nhave them run during your build stages. They can be tied into build tools such\nas Maven or Gradle \u0026 also into continuous integration tools.\n\n### Eclipse Memory Analyzer\n\nMemory leaks happen, even in Java. Luckily, there are tools for that. The best\ntool I've used to fix these is the [Eclipse Memory Analyzer][mat]. It takes a\nheap dump and lets you find the problem.\n\nThere's a few ways to get a heap dump for a JVM process, but I use\n[jmap][jmap]:\n\n```bash\n$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152\nAttaching to process ID 8152, please wait...\nDebugger attached successfully.\nServer compiler detected.\nJVM version is 23.25-b01\nDumping heap to heapdump.hprof ...\n... snip ...\nHeap dump file created\n```\n\nThen you can open the *heapdump.hprof* file with the Memory Analyzer and see\nwhat's going on fast.\n\n## Resources\n\nResources to help you become a Java master.\n\n### Books\n\n* [Effective Java](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683)\n* [Java Concurrency in Practice](http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601)\n* [Clean Code](http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/)\n\n### Podcasts\n\n* [The Java Posse](http://www.javaposse.com/) (*discontinued*)\n* [vJUG](http://virtualjug.com/)\n* [Les Cast Codeurs](https://lescastcodeurs.com/) (*French*)\n* [Java Pub House](http://www.javapubhouse.com/)\n* [Java Off Heap](http://www.javaoffheap.com/)\n* [Enterprise Java Newscast](http://www.enterprisejavanews.com)\n\n### Videos\n\n* [Effective Java - Still Effective After All These Years](https://www.youtube.com/watch?v=V1vQf4qyMXg)\n* [InfoQ](http://www.infoq.com/) - see especially [presentations](http://www.infoq.com/java/presentations/) and [interviews](http://www.infoq.com/java/interviews/)\n* [Parleys](https://www.parleys.com/)\n\n[immutablemap]: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html\n[immutablelist]: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableList.html\n[immutableset]: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableSet.html\n[depconverge]: https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html\n[copydir]: http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/FileUtils.html#copyDirectory(java.io.File,%20java.io.File)\n[writestring]: http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/FileUtils.html#writeStringToFile(java.io.File,%20java.lang.String)\n[readlines]: http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html#readLines(java.io.InputStream)\n[guava]: https://github.com/google/guava\n[cachebuilder]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/cache/CacheBuilder.html\n[immutablesorted]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableSortedMultiset.html\n[uninterrupt]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/Uninterruptibles.html\n[lists]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Lists.html\n[maps]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Maps.html\n[sets]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Sets.html\n[collections2]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Collections2.html\n[rootpom]: https://gist.github.com/cxxr/10787344\n[mavenexample]: http://books.sonatype.com/mvnex-book/reference/index.html\n[jenkins]: http://jenkins-ci.org/\n[travis]: https://travis-ci.org/\n[cobertura]: http://cobertura.github.io/cobertura/\n[coberturamaven]: http://mojo.codehaus.org/cobertura-maven-plugin/usage.html\n[nexus]: http://www.sonatype.com/nexus\n[artifactory]: http://www.jfrog.com/\n[mavenrepo]: http://stackoverflow.com/questions/364775/should-we-use-nexus-or-artifactory-for-a-maven-repo\n[artifactorymirror]: http://www.jfrog.com/confluence/display/RTF/Configuring+Artifacts+Resolution\n[gson]: https://github.com/google/gson\n[gsonguide]: https://sites.google.com/site/gson/gson-user-guide\n[joda]: http://www.joda.org/joda-time/\n[lombokguide]: http://jnb.ociweb.com/jnb/jnbJan2010.html\n[play]: https://www.playframework.com/\n[chef]: https://www.chef.io/chef/\n[puppet]: https://puppetlabs.com/\n[ansible]: http://www.ansible.com/home\n[squadron]: http://www.gosquadron.com\n[googlestyle]: http://google.github.io/styleguide/javaguide.html\n[googlepractices]: http://google.github.io/styleguide/javaguide.html#s6-programming-practices\n[di]: https://en.wikipedia.org/wiki/Dependency_injection\n[spring]: http://projects.spring.io/spring-framework/\n[springso]: http://programmers.stackexchange.com/questions/92393/what-does-the-spring-framework-do-should-i-use-it-why-or-why-not\n[java8]: http://www.java8.org/\n[javaslang]: http://javaslang.com/\n[javastream]: http://blog.hartveld.com/2013/03/jdk-8-33-stream-api.html\n[slf4j]: http://www.slf4j.org/\n[slf4jmanual]: http://www.slf4j.org/manual.html\n[junit]: http://junit.org/\n[testng]: http://testng.org\n[junitparam]: https://github.com/junit-team/junit/wiki/Parameterized-tests\n[junitrules]: https://github.com/junit-team/junit/wiki/Rules\n[junittheories]: https://github.com/junit-team/junit/wiki/Theories\n[junitassume]: https://github.com/junit-team/junit/wiki/Assumptions-with-assume\n[jmock]: http://www.jmock.org/\n[junitfixture]: https://github.com/junit-team/junit/wiki/Test-fixtures\n[initializingbean]: http://docs.spring.io/spring/docs/3.2.6.RELEASE/javadoc-api/org/springframework/beans/factory/InitializingBean.html\n[apachecommons]: http://commons.apache.org/\n[lombok]: https://projectlombok.org/\n[javatuples]: http://www.javatuples.org/\n[dontbean]: http://www.javapractices.com/topic/TopicAction.do?Id=84\n[nullable]: https://github.com/google/guice/wiki/UseNullable\n[optional]: http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html\n[jdbc]: http://docs.spring.io/spring/docs/4.0.3.RELEASE/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html\n[jooq]: http://www.jooq.org/\n[dao]: http://www.javapractices.com/topic/TopicAction.do?Id=66\n[gradle]: http://gradle.org/\n[intellij]: http://www.jetbrains.com/idea/\n[intellijexample]: http://i.imgur.com/92ztcCd.png\n[chronon]: http://blog.jetbrains.com/idea/2014/03/try-chronon-debugger-with-intellij-idea-13-1-eap/\n[eclipse]: https://www.eclipse.org/\n[dagger]: http://square.github.io/dagger/\n[guice]: https://github.com/google/guice\n[netbeans]: https://netbeans.org/\n[mat]: http://www.eclipse.org/mat/\n[jmap]: http://docs.oracle.com/javase/7/docs/technotes/tools/share/jmap.html\n[jrebel]: http://zeroturnaround.com/software/jrebel/\n[taint]: https://en.wikipedia.org/wiki/Taint_checking\n[checker]: http://types.cs.washington.edu/checker-framework/\n[customchecker]: http://types.cs.washington.edu/checker-framework/tutorial/webpages/encryption-checker-cmd.html\n[builderex]: http://jlordiales.me/2012/12/13/the-builder-pattern-in-practice/\n[javadocex]: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/ImmutableMap.Builder.html\n[dropwizard]: https://dropwizard.github.io/dropwizard/\n[jersey]: https://jersey.java.net/\n[springboot]: http://projects.spring.io/spring-boot/\n[spark]: http://sparkjava.com/\n[assertj]: http://joel-costigliola.github.io/assertj/index.html\n[jaxrs]: https://en.wikipedia.org/wiki/Java_API_for_RESTful_Web_Services\n[playdoc]: https://www.playframework.com/documentation/2.3.x/Anatomy\n[java8datetime]: http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html\n[checkedex]: http://docs.oracle.com/javase/7/docs/api/java/lang/Exception.html\n[the-worst-mistake-of-computer-science]: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/\n","funding_links":[],"categories":["Others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcxxr%2Fbetter-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcxxr%2Fbetter-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcxxr%2Fbetter-java/lists"}