Java has been my main language since I started programming more than 10 years ago. It has evolved quite a lot over the past years. There are many nice frameworks built around Java, such as Spring, Play, Akka, etc. This post gives a list of books and libraries in my opinion are very useful and would help Java engineers.
Books
Effective Java
In my opinion this is a must-read book for every Java programmer because it includes best practices on pretty much every aspect in Java. But be aware that this is not a beginner’s book which teaches about syntax. It helps you get to next level once you are comfortable coding in Java. The latest edition of the book is built around Java 7, 8 and 9. You should definitely keep this book on your shelf for references now and then.
Java Concurrency In Practice
Another must-read book. This is the best Java programming book to develop a rich understanding of concurrency and multithreading. Again this is not a beginner’s book but advanced programmers will find a lot of valuable insights. Concurrency and multithreading are very tricky to get right and this book would certainly help you write better concurrent code.
Clean Code
The name says it all. As an engineer, you’ll be reading code ― lots of code. And you will be challenged to think about what’s right about that code, and what’s wrong with it. More importantly, you will be challenged to reassess your professional values and your commitment to your craft.
This book is divided into three parts. The first describes the principles, patterns, and practices of writing clean code. The second part consists of several case studies of increasing complexity. Each case study is an exercise in cleaning up code―of transforming a code base that has some problems into one that is sound and efficient. The third part is the payoff: a single chapter containing a list of heuristics and “smells” gathered while creating the case studies. The result is a knowledge base that describes the way we think when we write, read, and clean code.
Java Performance: The Definitive Guide
Coding and testing are often considered separate areas of expertise. In this comprehensive guide, author and Java expert Scott Oaks takes the approach that anyone who works with Java should be equally adept at understanding how code behaves in the JVM, as well as the tunings likely to help its performance.
You’ll gain in-depth knowledge of Java application performance, using the Java Virtual Machine (JVM) and the Java platform, including the language and API. Developers and performance engineers alike will learn a variety of features, tools, and processes for improving the way Java 7 and 8 applications perform.
- Apply four principles for obtaining the best results from performance testing
- Use JDK tools to collect data on how a Java application is performing
- Understand the advantages and disadvantages of using a JIT compiler
- Tune JVM garbage collectors to affect programs as little as possible
- Use techniques to manage heap memory and JVM native memory
- Maximize Java threading and synchronization performance features
- Tackle performance issues in Java EE and Java SE APIs
- Improve Java-driven database application performance
Libraries
The following are Java libraries which I use quite often in my projects.
Guava
Guava is a set of core Java libraries from Google that includes new collection types (such as multimap and multiset), immutable collections, a graph library, and utilities for concurrency, I/O, hashing, caching, primitives, strings, and more! It is widely used on most Java projects within Google, and widely used by many other companies as well.
Guava comes in two flavors.
- The JRE flavor requires JDK 1.8 or higher.
- If you need support for JDK 1.7 or Android, use the Android flavor. You can find the Android Guava source in the
android
directory.
Apache Commons
Apache Commons is an Apache project focused on all aspects of reusable Java components.
The collection is huge and I found the following ones most useful:
Component | Description |
---|---|
IO | Collection of I/O utilities. |
Lang | Provides extra functionality for classes in java.lang. |
CSV | Component for reading and writing comma separated value files. |
Math | Lightweight, self-contained mathematics and statistics components. |
Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
Dagger
A fast dependency injector for Java and Android.
Dagger is a compile-time framework for dependency injection. It uses no reflection or runtime bytecode generation, does all its analysis at compile-time, and generates plain Java source code.
You can find the dagger documentation here which has extended usage instructions and other useful information. More detailed information can be found in the API documentation.
Jackson
Jackson has been known as “the Java JSON library” or “the best JSON parser for Java”. Or simply as “JSON for Java”.
More than that, Jackson is a suite of data-processing tools for Java (and the JVM platform), including the flagship streaming JSON parser / generator library, matching data-binding library (POJOs to and from JSON) and additional data format modules to process data encoded in Avro, BSON, CBOR, CSV, Smile, (Java) Properties, Protobuf, XML or YAML; and even the large set of data format modules to support data types of widely used data types such as Guava, Joda, PCollections and many, many more.
While the actual core components live under their own projects — including the three core packages (streaming, databind, annotations); data format libraries; data type libraries; JAX-RS provider; and a miscellaneous set of other extension modules — this project act as the central hub for linking all the pieces together.
JUnit 5
Unlike previous versions of JUnit, JUnit 5 is composed of several different modules from three different sub-projects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. It also defines the TestEngine
API for developing a testing framework that runs on the platform. Furthermore, the platform provides a Console Launcher to launch the platform from the command line and a JUnit 4 based Runner for running any TestEngine
on the platform in a JUnit 4 based environment. First-class support for the JUnit Platform also exists in popular IDEs (see IntelliJ IDEA, Eclipse, NetBeans, and Visual Studio Code) and build tools (see Gradle, Maven, and Ant).
JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a TestEngine
for running Jupiter based tests on the platform.
JUnit Vintage provides a TestEngine
for running JUnit 3 and JUnit 4 based tests on the platform.
Awaitility
Testing asynchronous systems is hard. Not only does it require handling threads, timeouts and concurrency issues, but the intent of the test code can be obscured by all these details. Awaitility is a DSL that allows you to express expectations of an asynchronous system in a concise and easy to read manner. For example:
@Test
public void updatesCustomerStatus() {
// Publish an asynchronous message to a broker (e.g. RabbitMQ):
messageBroker.publishMessage(updateCustomerStatusMessage);
// Awaitility lets you wait until the asynchronous operation completes:
await().atMost(5, SECONDS).until(customerStatusIsUpdated());
...
}
AssertJ
AssertJ is a java library providing a rich set of assertions, truly helpful error messages, improves test code readability and is designed to be super easy to use within your favorite IDE.
Here are a few examples of AssertJ assertions:
// entry point for all assertThat methods and utility methods (e.g. entry)
import static org.assertj.core.api.Assertions.*;
// basic assertions
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);
// chaining string specific assertions
assertThat(frodo.getName()).startsWith("Fro")
.endsWith("do")
.isEqualToIgnoringCase("frodo");
// collection specific assertions (there are plenty more)
// in the examples below fellowshipOfTheRing is a List<TolkienCharacter>
assertThat(fellowshipOfTheRing).hasSize(9)
.contains(frodo, sam)
.doesNotContain(sauron);
// as() is used to describe the test and will be shown before the error message
assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(33);
// exception assertion, standard style ...
assertThatThrownBy(() -> { throw new Exception("boom!"); }).hasMessage("boom!");
// ... or BDD style
Throwable thrown = catchThrowable(() -> { throw new Exception("boom!"); });
assertThat(thrown).hasMessageContaining("boom");
// using the 'extracting' feature to check fellowshipOfTheRing character's names
assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName)
.doesNotContain("Sauron", "Elrond");
// extracting multiple values at once grouped in tuples
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
.contains(tuple("Boromir", 37, "Man"),
tuple("Sam", 38, "Hobbit"),
tuple("Legolas", 1000, "Elf"));
// filtering a collection before asserting
assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o"))
.containsOnly(aragorn, frodo, legolas, boromir);
// combining filtering and extraction (yes we can)
assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o"))
.containsOnly(aragorn, frodo, legolas, boromir)
.extracting(character -> character.getRace().getName())
.contains("Hobbit", "Elf", "Man");
// and many more assertions: iterable, stream, array, map, dates, path, file, numbers, predicate, optional ...
Mockito
Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.
In mockito, we generally work with following kind of test doubles.
- Stubs – is an object that has predefined return values to method executions made during the test.
- Spies – are objects that are similar to stubs, but they additionally record how they were executed.
- Mocks – are objects that have return values to method executions made during the test and has recorded expectations of these executions. Mocks can throw an exception if they receive a call they don’t expect and are checked during verification to ensure they got all the calls they were expecting.
We can mock both interfaces and classes in the test class. Mockito also helps to produce minimum boilerplate code while using mockito annotations.
Mapstruct
MapStruct is a Java annotation processor for the generation of type-safe and performant mappers for Java bean classes. It saves you from writing mapping code by hand, which is a tedious and error-prone task. The generator comes with sensible defaults and many built-in type conversions, but it steps out of your way when it comes to configuring or implementing special behavior.
Compared to mapping frameworks working at runtime, MapStruct offers the following advantages:
- Fast execution by using plain method invocations instead of reflection
- Compile-time type safety. Only objects and attributes mapping to each other can be mapped, so there’s no accidental mapping of an order entity into a customer DTO, etc.
- Self-contained code—no runtime dependencies
- Clear error reports at build time if:
- mappings are incomplete (not all target properties are mapped)
- mappings are incorrect (cannot find a proper mapping method or type conversion)
- Easily debuggable mapping code (or editable by hand—e.g. in case of a bug in the generator)