How can I package a Java desktop application?

Users of your Java app must have the JRE installed in order to run it.
You can either tell them to install Java first, or distribute JRE with your app, as Processing does.
Note, however, that your packaged program will be heavy if you include JRE with it. And, if you want to do that, users will need to download the appropiate package for their platform.

Executable Java Wrappers

They take your Java app as input and wrap them in an executable (for a specified platform). You can customize them as you like; and if the user doesn't have Java installed, the download page will open.

Some examples are Launch4J, JSmooth and Jar2EXE.
 

Installers

They are independent applications configured to copy your app files to the user's computer and (optionally) create a shortcut.

Some installers are written in Java, so they're multiplatform. In this case, the installer is a .jar.
Some others are platform-dependent, but you have the advantage that you don't need to wrap them.

Java installers: IzPack, Packlet, PackJacket, Antigen, …
 

Java Web Start

It's a Java feature that allows you users to easily run your apps. You give them a .jnpl file,
they open it, and Java downloads the latest version of your app and runs it. No packaging troubles!


See the complete list of resources here.


Bundle JVM within your app

The modern solution to deploying a Java-based desktop app is to bundle a JVM with your app, delivered to the user as a double-clickable package just like other "normal" apps. Think of the JVM as another dependency to be incorporated within your final app.

Learn about:

  • Java Platform Module System
  • jlink (JEP 282)
  • JEP 220: Modular Run-Time Images
  • jpackage (JEP 343)

You could ship a JavaFX (OpenJFX) app this way, as well as a Swing app (the predecessor to JavaFX).

One advantage of this approach is that you know exactly what JVM is being used to run your particular app. Of course it also means you must release a new version of your app when a JVM update contains a relevant fix. Your users no longer are concerned with downloading, installing, and upgrading a JVM, as that chore is now the responsibility of the developer.

One disadvantage of this approach is that you must build, test, and distribute separate binaries of your app, one for each platform (macOS, MS Windows, BSD, Linux, and so on).

See also my Answer on a related Question, How to use jdk without jre in Java 11.

See the Answer by Will Iverson for what looks like some useful tooling.

Compiled native app

GraalVM

A cutting-edge variation of this approach is to build an ahead-of-time-compiled (versus JIT) native-code version of your app using GraalVM and its native image generator.

Project Leyden

Possibly related: Oracle's Project Leyden. See initial announcement by Mark Reinhold, and see this article, 2020-05-07.

Java Web Start phase-out

Some other Answers discuss Java Web Start. Be aware that Java Web Start and Java Applets technologies are both being phased out by Oracle. See their white paper, Java Client Roadmap Update dated 2020-05-11.

A possible alternative is the open-source implementation of Java Web Start known as the OpenWebStart project.