Maven vs Gradle equivalent commands

I’ve seen Gradle becoming more popular in recent years, but it wasn’t too long ago that Maven was the tool for managing dependencies and building/packaging apps.

From my own experience with both, here’s the commonly used equivalent commands:

MavenGradle
mvn compileNo equivalent as gradle build compiles and packages?
mvn packagegradle build
mvn install (see note below)gradle build
mvn testgradle test

There is no direct equivalent to ‘mvn install’ in gradle, but if you depend on a local Maven repo, there is a Gradle plugin to publish packaged artifacts to a Maven repo – see here.

Initializing new Java projects with Gradle

I’ve used Maven for years for dependency management, but Gradle has better support for initializing a new Java source project compared to Maven. Although Maven has archetypes, I can never remember the syntax so usually just copy and paste a pom.xml file from somewhere else.

With Gralde you can ‘gradle init’ a new project and just follow the prompts:

> gradle init

Welcome to Gradle 8.1.1!

Here are the highlights of this release:
 - Stable configuration cache
 - Experimental Kotlin DSL assignment syntax
 - Building with Java 20

For more details see https://docs.gradle.org/8.1.1/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Generate multiple subprojects for application? (default: no) [yes, no] n                          nolease enter 'yes' or 'no': 
Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 1

Project name (default: java21playground): 
Source package (default: java21playground): 
Enter target version of Java (min. 7) (default: 21): 
Generate build using new APIs and behavior (some features may change in the next minor release)? (no


> Task :init
Get more help with your project: https://docs.gradle.org/8.1.1/samples/sample_building_java_applications.html

BUILD SUCCESSFUL in 1m 7s
2 actionable tasks: 2 executed

With Maven you add your dependencies to a <dependencies> block in your pom.xml, like

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Dependencies with the default scope are considered part of your compile and runtime classpath, <scope>test</scope> indicates on the test classpath only.

With Gradle you do the same with your build.gradle properties file, in the dependencies section:

dependencies {
    testImplementation 'junit:junit:4.13.2'

    implementation 'com.google.guava:guava:31.1-jre'
}

implementation dependencies are for runtime, testimplementation are for test only.

Java functions and functional interfaces

I have enough knowledge of Lambdas In Java to be able to use them where useful, but under the covers there’s more to how functions are defined and referenced using the interfaces in java.util.function. Here’s a few notes digging into more details on implementing functions in Java.

java.util.function interfaces

Java interfaces used to define types for Lambda expressions and method references:

interface Function<T, R>
Defines a function which takes a parameter of type T and returns a result of type R

Single argument functions:

interface Consumer<T>
A function that takes a parameter of type T but with no return value. Provides single function void accept(T)

interface Supplier<T>
A function that takes no argument but returns a result of type T. Provides single functional method T get()

To define a function that doesn’t take any parameters or return a result can be represented by interface Java.lang.Runnable

All other interfaces in java.util,function are variations of Provider and Supplier, such as …

Bi Function interfaces

BiFunction<T, U, R>
A function that takes 2 parameters of type T and U and returns result of type R

BiConsumer<T, U>
A function that takes 2 parameters of types T and U but no return type.

Other interfaces

Boolean Predicate<T>
A function that takes a parameter of type T and returns a Boolean result. Example usage is for a filter function on Streams

BiPredicate<T, U>

<T> UnaryOperator<T>
Special case of Function that takes an argument and returns the result of the same type

<T> BinaryOperator<T>

Takes 2 parameters of the type and results a result of the same type

Method references

Method references use the :: syntax to refer to a static method that exists on a Class and pass this as a reference in place of a Lambda. For example System.out::println

To print each element of a list you could pass a Lambda calling println for each item:

list.forEach( item -> System.out.println(item)):

but using a method reference simplifies this to:

list.forEach(System.out::println);

Method references implement a functional interface but instead of implementing a new method like with a Lambda, a Method reference points to a method that already exists in a Class.

Mwthod references can be used to a static method with

Typename::staticMethodName

or to a method on an instance with

instanceName::instanceMethodName

Quick tip of the day: While learning Java, avoid defining anything as static

If you’re just starting out and learning Java, avoid the temptation of defining anything as static until you understand what this modifier does and why/when you need to use it: no static Class properties, no static methods.

The only use of static while you’re starting out is in your main method. You don’t need it anywhere else. You’ll avoid a lot of unexpected and unexplainable behavior as a result.