Java CLI
Introduction
Java is not only the name of the programming language but also the name of the
CLI responsible for the execution of Java programs on the JVM. Next to the
java command, which is included in the Java Runtime Environment (JRE) and
the Java Development Kit (JDK), there is also the javac command which is
responsible for the compilation of Java source code. As such javac is only
part of the JDK.
Those two commands are essential for the development of Java applications, tough they are most often hidden behind other programs. Many Java Programms get wrapped in an executable file and the build is done by a build tool like Maven or Gradle.
Compilation
The compilation of Java source code (.java files) into Java bytecode (.class
Files) is done with the javac command. Depending on the size of the project
and the number of source files, it makes sense to approach the compilation
differently.
Single Files
To compile single .java files, the javac command can be called with the
desired options followed by the files to be compiled. Here the path to the Java
file needs to be specified in terms of the file system and not the package.
After running the javac command it either fails by outputting an error message
detailing what went wrong during the compilation of the program. If no error
appears the class was successfully compiled and a file with the same name but
suffix .class was created. This file contains the Java bytecode which can be
run with java.
$ ls -l
total 4
-rw-r--r-- 1 liam liam 106 Sep 26 17:10 Main.java
$
$ javac Main.java
$ ls -l
total 8
-rw-r--r-- 1 liam liam 415 Sep 26 17:17 Main.class
-rw-r--r-- 1 liam liam 106 Sep 26 17:17 Main.java
$
$ java Main
Hello, World!
If more than one Java file needs to be compiled, multiple files can be listed.
They then get compiled with the same call to javac.
Complete Applications
If an entire application needs to be compiled, it is cumbersome to list each Java file individually. Here are two good options to simplify the compilation.
The first options uses the -sourcepath option. This allows to compile files
based on their dependencies. The -sourcepath option is followed by the path
to the Java source directory. This source directory needs to contain the source
package of the application. After the source path, the path to the class with
the public static void main(String[] args) method is specified.
$ tree src
src
└── com
└── example
├── Greeter.java
└── Main.java
2 directories, 2 files
$
$ javac -sourcepath ./src -d ./target src/com/example/Main.java
$
$ tree target
target
└── com
└── example
├── Greeter.class
└── Main.class
2 directories, 2 files
In this way, all classes that depend on the Main class and its dependencies are
automatically compiled. This is also the problem with this method, a class that
is not referenced is not compiled. To circumvent this problem, the javac
command can be executed with an argument file that contains all classes.
This file can then be extended when creating a new class to the application or
even directly using the find command.
$ tree src
src
└── com
└── example
├── Greeter.java
└── Main.java
2 directories, 2 files
$
$ find ./ -type f -name "*.java" > sources.txt
$
$ cat sources.txt
./src/com/example/Main.java
./src/com/example/Greeter.java
./src/com/example/Unreferenced.java
$
$ javac -d ./target @sources.txt
$
$ tree target/
target/
└── com
└── example
├── Greeter.class
├── Main.class
└── Unreferenced.class
2 directories, 3 files
Java Archive (JAR)
When the compiled application should distributed, it is annoying to need to
distribute each and ever .class file. Therefore Java provides the Java Archive.
The Java Archive is a compressed file that contains all the compiled classes and
still allows people to run the application.
To create such a Java Archive the jar command is used. The jar command takes
all the .class files and any other resources that are needed.
$ jar -cvfe App.jar com.example.Main -C target .
added manifest
adding: com/(in = 0) (out= 0)(stored 0%)
adding: com/example/(in = 0) (out= 0)(stored 0%)
adding: com/example/Greeter.class(in = 412) (out= 293)(deflated 28%)
adding: com/example/Main.class(in = 336) (out= 255)(deflated 24%)
adding: com/example/Unreferenced.class(in = 210) (out= 175)(deflated 16%)
$
$ java -jar App.jar
Hello, World!
Execution
A compiled Java application is all well and good, but if you can’t run it it’s
not worth much.
For this purpose the java command is used. It makes sure that the compiled
application is run on the JVM.
Bytecode
When a given application exists in form of Java bytecode (.class files), the
application can be run using the java command. For this the java command
must be run with the name of the class wich contains the entry point (the
public static void main(String[] args) method). The name of this class needs
to be specified in Form of it’s fully qualified name. In example
com.example.Main and not com/example/Main. For this command to work it
either needs to be executed in the source directory of the application or the
path to the source directory needs to be specified using the -classpath
option.
$ ls -l
total 8
-rw-r--r-- 1 liam liam 415 Sep 26 17:17 Main.class
-rw-r--r-- 1 liam liam 106 Sep 26 17:17 Main.java
$
$ java Main
Hello, World!
Or if the application consists of multiple classes:
$ tree classes/
classes/
└── com
└── example
├── Greeter.class
└── Main.class
2 directories, 2 files
$
$ java -cp classes/ com.example.Main
Hello, World!
Java Archive (JAR)
The java command can also be used to execute Java Archives, for this the
-jar option and the path to the JAR must be specified.
$ java -jar App.jar
Hello, World!
Useful Options
When compiling and running Java programs there are some useful options that can
passed to the javac and java commands to make life easier.
Compilation
-d <directory>: This option allows you to specified the directory where the compiledclass-files will be stored. This is useful when you want to keep the source and compiled files separate.
$ javac -d ./bin ./src/Main.java
-sourcepath <directory>: The-sourcepathdirectory specifies where the compiler should look for other.javafiles that the file being compiled depends on. This is useful when you have a project with many classes that depend on each other.
$ javac -sourcepath ./src ./src/Main.java
-cp <path>or-classpath <path>: This option set the search path for user class files and annotation processors. If you use libraries or other classes that are not in the current directory, you need to use this option to tell the compiler where it can find them.
$ javac -cp ./lib/* ./src/Main.java
Execution
-cp <path>or-classpath <path>: This option, like when compiling, sets the search path for application classes and resources.
$ java -cp ./bin Main
-Xmx<size>: This option sets the maximum size of the memory heap. If you have an application with high memory requirements, you can use this option to increase the amount of memory available to the JVM.
$ java -Xmx512m -cp ./bin Main
-jar <filename>: This option specifies the JAR file to be executed.
$ java -jar ./dist/App.jar
-D<name>=<value>: This option allows you to define a system property that can be retrieved by your application.
$ java -Dapp.env=production -cp ./bin Main
Last updated 08 Jan 2025, 17:05 +0100 .
What did you like?
What went wrong?