Java is a general-purpose programming language introduced little over 20 years ago. It has become widely popular in the enterprise space due to the Java Virtual Machine, the Garbage Collector, a similar programming model to C/C++ and the promise of easier-to-write programs than its competitors of the time.
It is statically typed, notorious for a proliferation of
null, and relies on polymorphism for clever solutions to problems.
Since Java 8, more and more functional programming elements have found their way into the language, such as
Optional<T>, making a resurgence since the more traditional Java 6 and 7 releases.
- Download from the offical site
- Official JavaDocs
- Java Tutorials: docs.oracle.com
- Java Koans to learn the language a single test at a time
Topics, Tools and Terms
Java packages are distributed in jars (from Java archive). The central repository to download these jars from is Maven central.
The Java Virtual Machine (short: JVM) is the platform all Java programs run on. It allows Java code to be operating system agnostic, meaning that a Java program written on MacOS can be compiled and run on Windows without modification.
Gradle is not just a tool for build or dependency management, it supports the whole life-cycle for Java projects. That includes compiling, testing, packaging, releasing and deploying a project. Gradle can be expanded with custom tasks for specific needs of the project. You can find out more about writing tasks in the official documentation
Java dependencies are called jars. There multiple established tools (Maven, Ivy, Gradle, sbt) to declare and manage Java dependencies. These tend to come bundled with some kind of task execution framework. In this guide we will focus on Gradle to maintain our Java projects, though we will lean heavily on standard and practices inspired by Maven.
Start out by creating an initial scaffolding with
gradle init --type java-application.
This will create the basic files and folder that form the core structuer of a Gradle application.
For the time being, lets focus on the
build.gralde file. It defines our project, its dependencies, and any tasks that we’d need to run.
The inital setup has created a minimal skeleton of a
build.gradle file (comments ommited):
// Plugins are a way to share common configuration settings between projects
// Apply the java plugin to add basic support for Java, while the `application`
// adds some basic tasks to package up our application when its ready.
apply plugin: 'java'
apply plugin: 'application'
// Where to get dependencies from. JCenter is the largest repository of jars and very reputable
// This is where we will declare our dependnecies
// Define the main class for the application, which is part of the `application` plugin
mainClassName = 'App'
Let us focus on the
dependencies block to learn how to maintain our project dependencies.
Dependening on whether you need the dependency as part of your production code or only as part of the testing infrastructue you’ll need to declare you dependency as part of the
compile configuration or the
In the above example, the JUnit jar has been added to to the
testCompile configuration as there is no use for it as part of the finished application.
The string in single-quotes represents the Maven Artifact notation, namely the groupId, the artifactId, and the version.
This allows Gradle to pinpoint the depedency, locate it in the repository, and download it wiht its dependencies.
If we wanted to add the Apache Commons Language utilities in version 3.6 we would write the following:
There are more configurations such as
testRuntime that are used for specialised purposes. See the Gradle Documentation for more details.
Version managers allow us to quickly switch between different language versions. There’s no support to automatically install new versions, though. With Java this is a manual process.
The standard testing framework is called JUnit.
JUnit is primarily a runner for our tests, and it comes with it’s own matchers like
There are alternatives to that, which provide a more fluent way to express expectations of a test.
One other matcher library is Hamcrest. It supports exepectations in the style of
compared to the more traditional JUnit style
Another one is AssertJ, which allows expectations in the style of
JUnit itself comes with Hamcrest bundled automatically, so in this guide and the example application we will be using Hamcrest style assertions.
The directory structure for a Gradle project using the
maven plugin consists of a
src directory that has two sub-directories:
mainfor the production code.
testfor the tests.
Inside each of those it’s possible to have a
resources directory to contain general assets for the project like images or configuration files.
We provided a working example of a minimal project on Github.
Every subdirectory inside each
java directory forms a package.
Packages are Java’s way to give classes that belong together a namespace.
Package names are in lower case.
File names of classes reflect the class name including the capital first letter.
For example the class
Vanilla needs to be contained in file
Tests match their production code file names with a
Test suffix, e.g. tests for code in
Vanilla.java should be written in
They also match their production package, so that class
com.vanilla_project.Vanilla will have its tests in
While the package names match, the physical location does not (as they’re separated by
The repository for the example application is available at github.com/vanilla-project/java-gradle-command-line.
The main application consists of basically three files:
Main.javais the main executable that instantiates and runs:
App.javacontains the main application that uses:
Example.javawhich contains only one method that returns a string.
Running the Application
To run the application we need to build it first.
This can be done by executing the
jar task of gradle
This will download all dependencies, compile the code, run the tests and package it up into a
We can then execute the jar file to run our application:
Running the Tests
To run the tests we execute
gradle test which then looks for all files inside directory
src/test and runs them.
The output should look like the following:
$: gradle test
BUILD SUCCESSFUL in 0s
3 actionable tasks: 3 up-to-date
The test for class
Example is only verifying the return value of one method.
App on the other hand is tested via a test-double that gets injected.
This allows us to spy on the output of it.
We want to avoid printing anything to the screen while running the tests.
Injecting a test double in this instance is a nice way to isolate our application from the command line.
In the actual
Main class we then inject
System.out, which is Java’s standard output stream.