How to Run Java Programs in Linux Terminal
Running Java programs directly from the Linux terminal offers developers enhanced control, automation capabilities, and a deeper understanding of Java’s execution process. Whether you’re a student learning programming basics or a seasoned developer working on complex applications, mastering command-line Java execution is an invaluable skill that will boost your productivity and versatility in Linux environments.
This comprehensive guide walks you through everything you need to know about compiling and running Java programs in the Linux terminal. You’ll learn how to set up your environment, understand the compilation process, work with packages and libraries, and troubleshoot common issues that arise during development.
Prerequisites for Running Java in Linux
Before diving into Java development on Linux, ensure you have the necessary foundation to work efficiently with the terminal and understand basic programming concepts.
Required Skills and Tools:
The Linux terminal provides powerful functionality once you become familiar with its interface. To get started effectively, you’ll need:
- Basic familiarity with Linux terminal commands including navigation (
cd
,ls
), file manipulation (cp
,mv
,rm
), and viewing file contents (cat
,less
) - A functioning Linux distribution (Ubuntu, Debian, Fedora, CentOS, or any other distribution)
- Sufficient system resources (most modern computers easily meet Java’s requirements)
- Understanding of fundamental programming concepts like variables, conditionals, and loops
For writing your Java code, Linux offers several excellent text editors:
- Vim or Neovim: Highly efficient editors with extensive customization options
- Emacs: Another powerful editor with comprehensive programming features
- Nano: A simpler, more beginner-friendly editor
- Visual Studio Code: A popular GUI editor with excellent Java support
- IntelliJ IDEA: A full-featured IDE available in community edition
Remember that while IDEs provide convenience, learning to compile and run programs from the terminal gives you greater control and understanding of the underlying processes.
Installing Java Development Kit (JDK) in Linux
The Java Development Kit (JDK) provides all the tools needed to develop, compile, and run Java applications on your Linux system.
Checking for Existing Java Installation:
Before installing a new JDK, verify whether Java is already installed on your system:
java -version
javac -version
If these commands return version information, you already have Java installed. If not, you’ll need to install the JDK using your distribution’s package manager.
Installation Methods for Different Linux Distributions:
For Ubuntu/Debian-based systems:
# Update package lists
sudo apt update
# Install OpenJDK (version 17 shown here)
sudo apt install openjdk-17-jdk
# Verify installation
java -version
javac -version
For Fedora/RHEL systems:
# Install OpenJDK using dnf
sudo dnf install java-17-openjdk-devel
# Verify installation
java -version
javac -version
For Arch Linux:
# Install using pacman
sudo pacman -S jdk-openjdk
# Verify installation
java -version
javac -version
Using SDKMAN for Version Management:
SDKMAN is a useful tool for managing multiple Java versions on any Linux distribution:
# Install SDKMAN
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# List available Java versions
sdk list java
# Install desired version
sdk install java 17.0.2-open
# Verify installation
java -version
OpenJDK vs Oracle JDK:
When choosing which JDK to install, you have two main options:
- OpenJDK: The free, open-source implementation of the Java Platform
- Oracle JDK: Oracle’s proprietary implementation with some additional features
For most development purposes, OpenJDK is perfectly suitable and avoids licensing complications. However, if you need specific Oracle features or support, you might consider Oracle JDK.
Setting Up Java Environment Variables
Properly configuring environment variables ensures your system can locate and use Java correctly for all your development needs.
Configuring JAVA_HOME:
The JAVA_HOME environment variable points to your Java installation directory and is required by many Java applications and build tools:
# Find your Java installation path
which java
# For symbolic links, find the actual installation
readlink -f $(which java)
# The result will be something like /usr/lib/jvm/java-17-openjdk-amd64/bin/java
# JAVA_HOME should be the directory containing "bin"
Set JAVA_HOME for your current session:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
Adding Java to PATH:
The PATH variable tells your system where to find executable files:
export PATH=$PATH:$JAVA_HOME/bin
Making Environment Variables Permanent:
To make these settings persist across terminal sessions, add them to your shell profile:
# For bash users (add to ~/.bashrc)
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> ~/.bashrc
echo 'export PATH=$PATH:$JAVA_HOME/bin' >> ~/.bashrc
source ~/.bashrc
# For zsh users (add to ~/.zshrc)
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> ~/.zshrc
echo 'export PATH=$PATH:$JAVA_HOME/bin' >> ~/.zshrc
source ~/.zshrc
Testing Your Configuration:
Verify that your environment variables are set correctly:
echo $JAVA_HOME
echo $PATH
java -version
javac -version
If all commands return the expected values, your environment is configured correctly.
Understanding Java Program Structure
To effectively compile and run Java programs, you must understand their basic structure and components.
Basic Components of a Java Program:
A simple Java program contains:
- Optional package declaration (namespace)
- Optional import statements for external classes
- Class declaration
- Main method (entry point)
Here’s a basic example:
// Optional package declaration
package com.example.myapp;
// Optional import statements
import java.util.Scanner;
// Class declaration
public class HelloWorld {
// Main method - the program entry point
public static void main(String[] args) {
System.out.println("Hello, Linux world!");
// Using imported classes
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hello, " + name + "!");
scanner.close();
}
}
The main
method is particularly important as it serves as the entry point for your application. Java looks for this method when you execute a class, and its signature must match exactly as shown above.
Compiling Java Programs
The compilation process transforms human-readable Java code (.java files) into bytecode (.class files) that the Java Virtual Machine (JVM) can execute.
Basic Compilation:
To compile a simple Java program:
# Create a file named HelloWorld.java with your code
nano HelloWorld.java
# Compile the file
javac HelloWorld.java
After successful compilation, you’ll see a new file named HelloWorld.class
in the same directory. This file contains the bytecode that the JVM will execute.
Understanding the Compilation Process:
When you run javac
, the compiler:
- Parses your Java code
- Checks for syntax errors
- Analyzes the code for semantic correctness
- Generates bytecode if no errors are found
Common Compilation Errors:
You might encounter various errors during compilation:
- Syntax errors: Missing semicolons, brackets, or misspelled keywords
- Type errors: Assigning incompatible data types
- Reference errors: Using undefined variables, methods, or classes
The Java compiler provides descriptive error messages with line numbers to help you identify and fix these issues.
Compilation Options:
The javac
command offers numerous options to customize the compilation process:
# Specify output directory for .class files
javac -d bin HelloWorld.java
# Compile with debugging information
javac -g HelloWorld.java
# Specify source and target Java versions
javac -source 11 -target 11 HelloWorld.java
# Enable additional warnings
javac -Xlint HelloWorld.java
Compiling Multiple Files:
For projects with multiple Java files:
# Compile specific files
javac File1.java File2.java File3.java
# Compile all Java files in the current directory
javac *.java
# Compile all Java files recursively
find . -name "*.java" > sources.txt
javac @sources.txt
Running Java Programs
Once compiled, you can execute your Java programs using the java
command.
Basic Execution:
To run a simple Java program:
# Run the program (note: don't include the .class extension)
java HelloWorld
The java
command loads the JVM, which then reads the bytecode, performs just-in-time compilation, and executes your program.
Running Programs with Packages:
If your program uses packages, you need to run it from the base directory:
# For a program in package com.example.myapp
# Navigate to the directory above the package root
cd ~/projects/java-demo
# Run the program using the fully qualified class name
java com.example.myapp.HelloWorld
Passing Command-Line Arguments:
You can pass arguments to your Java programs through the command line:
java HelloWorld arg1 arg2 arg3
In your code, access these arguments through the args
parameter in the main method:
public static void main(String[] args) {
// args[0] is "arg1", args[1] is "arg2", etc.
System.out.println("First argument: " + args[0]);
}
Running with Custom JVM Options:
The java
command accepts various options to customize the JVM’s behavior:
# Set maximum heap size
java -Xmx512m HelloWorld
# Enable verbose garbage collection
java -verbose:gc HelloWorld
# Combine multiple options
java -Xms256m -Xmx1g -ea HelloWorld
Working with Java Packages
Packages help organize Java code, prevent naming conflicts, and control access to classes and methods.
Creating Package Structures:
Package names correspond to directory structures:
# For package com.example.myapp
mkdir -p com/example/myapp
# Create a Java file in this package
nano com/example/myapp/HelloWorld.java
Inside HelloWorld.java:
package com.example.myapp;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello from a package!");
}
}
Compiling and Running Packaged Programs:
Compile from the root directory:
# Compile
javac com/example/myapp/HelloWorld.java
# Run
java com.example.myapp.HelloWorld
Package Naming Conventions:
Follow these standard conventions for package names:
- Use lowercase letters
- Use reversed domain name (e.g., com.example.project)
- Separate logical components with dots
- Avoid Java reserved keywords
Importing Classes from Other Packages:
Use import statements to use classes from other packages:
// Single class import
import java.util.ArrayList;
// Entire package import
import java.util.*;
Managing Class Paths
The classpath tells Java where to find user-defined classes and packages when compiling and running programs.
Understanding the Classpath:
The classpath is a parameter that specifies the location of user-defined classes and packages. It can include directories, JAR files, and ZIP archives.
Using the -cp Option:
Specify the classpath when compiling or running Java programs:
# Compile with classpath
javac -cp ".:lib/dependency.jar" com/example/myapp/HelloWorld.java
# Run with classpath
java -cp ".:lib/dependency.jar" com.example.myapp.HelloWorld
The colon :
separates classpath entries on Linux (use semicolon ;
on Windows).
Setting CLASSPATH Environment Variable:
You can set a default classpath through the CLASSPATH environment variable:
export CLASSPATH=.:lib/dependency.jar
However, explicitly using the -cp
option is generally preferred for clarity and to avoid unexpected behavior.
Directory Structure Best Practices:
Organize your Java projects with a clear structure:
project/
├── src/ # Source files
│ └── com/
│ └── example/
│ └── myapp/
│ └── HelloWorld.java
├── bin/ # Compiled classes
├── lib/ # External libraries
└── docs/ # Documentation
Working with External Libraries
Most real-world Java applications use external libraries to extend functionality without reinventing the wheel.
Adding JAR Files to Your Project:
Place JAR files in a dedicated directory (e.g., lib/
):
mkdir -p lib
# Download or copy JAR files to this directory
Compiling with External Dependencies:
Include JAR files in the classpath when compiling:
javac -cp ".:lib/*" com/example/myapp/HelloWorld.java
Running with External Dependencies:
Similarly, include JAR files in the classpath when running:
java -cp ".:lib/*" com.example.myapp.HelloWorld
Using Build Tools from Terminal:
For complex projects with many dependencies, consider using build tools:
Maven:
# Create a new Maven project
mvn archetype:generate -DgroupId=com.example -DartifactId=myapp
# Compile and package
cd myapp
mvn compile
mvn package
# Run the packaged JAR
java -jar target/myapp-1.0-SNAPSHOT.jar
Gradle:
# Create a new Gradle project
mkdir gradle-demo && cd gradle-demo
gradle init --type java-application
# Build and run
./gradlew build
./gradlew run
These build tools automatically manage dependencies, compilation, and packaging, greatly simplifying the development process for larger projects.
Running JAR Files
JAR (Java ARchive) files bundle Java classes and resources into a single file, making distribution and execution more convenient.
Creating Executable JAR Files:
Create a manifest file (manifest.txt) that specifies the main class:
Main-Class: com.example.myapp.HelloWorld
Create the JAR file:
jar cvfm HelloWorld.jar manifest.txt com/example/myapp/HelloWorld.class
Running JAR Files:
Execute the JAR file:
java -jar HelloWorld.jar
Setting Executable Permissions:
Make the JAR file executable:
chmod +x HelloWorld.jar
This allows you to run it directly (if your system is configured to use the Java launcher for .jar files).
Creating JAR Files with Dependencies:
For JAR files that depend on external libraries:
# Create a directory for all classes
mkdir -p classes
# Compile with dependencies to the classes directory
javac -cp "lib/*" -d classes src/com/example/myapp/*.java
# Create the JAR with the manifest
jar cvfm app.jar manifest.txt -C classes .
Advanced Java Execution Options
The JVM offers numerous options to fine-tune execution for performance, debugging, and monitoring.
Memory Allocation:
Control memory allocation for your Java applications:
# Set maximum heap size
java -Xmx512m HelloWorld
# Set initial heap size
java -Xms128m HelloWorld
# Combine options
java -Xms128m -Xmx512m HelloWorld
Debugging Options:
Enable remote debugging for connection with debugging tools:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 HelloWorld
Performance Monitoring:
Monitor JVM performance during execution:
# Print garbage collection details
java -verbose:gc HelloWorld
# JIT compiler statistics
java -XX:+PrintCompilation HelloWorld
Logging and Output Redirection:
Direct standard output and error streams to files:
java HelloWorld > output.log
java HelloWorld > output.log 2> error.log
These advanced options give you fine-grained control over how your Java applications run and help diagnose issues that arise during execution.
Troubleshooting Common Issues
Even experienced developers encounter issues when working with Java in the terminal. Here are solutions for common problems.
ClassNotFoundException and NoClassDefFoundError:
These common errors occur when Java cannot find a class:
- ClassNotFoundException: Thrown when trying to load a class through its string name
- NoClassDefFoundError: Thrown when a class was available during compilation but not found during runtime
Solutions:
- Check your classpath to ensure it includes all necessary directories and JAR files
- Verify that the class exists and is properly compiled
- Confirm that package names match directory structure exactly
Classpath Configuration Problems:
Symptoms of classpath issues include classes not found despite being present or wrong versions of classes being loaded.
Solutions:
- Explicitly specify the classpath with
-cp
rather than relying on the CLASSPATH environment variable - Use absolute paths if relative paths aren’t working
- Check for classpath conflicts where multiple versions of the same class exist
Package Structure Mismatches:
The package declaration must match the directory structure exactly:
// File: com/example/myapp/HelloWorld.java
package com.example.myapp; // Must match directory structure
Permission and File Access Issues:
If encountering permission issues:
# Check file permissions
ls -l HelloWorld.java HelloWorld.class
# Set appropriate permissions
chmod 644 HelloWorld.java
chmod 755 HelloWorld.class
JDK Version Compatibility Problems:
Different Java versions have different features and syntax:
# Check your Java version
java -version
# Compile for specific version compatibility
javac -source 11 -target 11 HelloWorld.java
Automating Java Compilation and Execution
Automate repetitive tasks to improve efficiency during development.
Creating Shell Scripts:
Create a build script (build.sh):
#!/bin/bash
# Simple build script for Java projects
# Clean previous build
rm -rf bin
mkdir -p bin
# Compile
javac -d bin src/com/example/myapp/*.java
# Run
java -cp bin com.example.myapp.HelloWorld
echo "Build and run complete."
Make it executable:
chmod +x build.sh
Using Makefiles:
Create a Makefile for more advanced automation:
JAVAC = javac
JAVA = java
SRC_DIR = src
BIN_DIR = bin
PACKAGE = com/example/myapp
MAIN_CLASS = com.example.myapp.HelloWorld
.PHONY: all clean run
all: $(BIN_DIR)
$(JAVAC) -d $(BIN_DIR) $(SRC_DIR)/$(PACKAGE)/*.java
$(BIN_DIR):
mkdir -p $(BIN_DIR)
clean:
rm -rf $(BIN_DIR)
run: all
$(JAVA) -cp $(BIN_DIR) $(MAIN_CLASS)
Use with:
make # Compile
make run # Compile and run
make clean # Clean build files
These automation tools significantly reduce the amount of manual work required during development and help ensure consistency in your build process.
Best Practices for Terminal-Based Java Development
Follow these practices to develop efficiently in the terminal.
Directory Organization:
Maintain a clean project structure:
- Keep source files in
src/
- Output compiled classes to
bin/
- Store libraries in
lib/
- Document your code in
docs/
Version Control Integration:
Use Git with your terminal workflow:
# Initialize repository
git init
# Create .gitignore for Java
echo "bin/\n*.class\n.classpath\n.project" > .gitignore
# Standard Git workflow
git add .
git commit -m "Initial commit"
Documentation Approaches:
Document your code using Javadoc:
/**
* This class demonstrates a simple Java program.
*
* @author Your Name
* @version 1.0
*/
public class HelloWorld {
/**
* Program entry point.
*
* @param args command-line arguments
*/
public static void main(String[] args) {
System.out.println("Hello, documented world!");
}
}
Generate documentation:
javadoc -d docs src/com/example/myapp/*.java
Testing from the Command Line:
Run JUnit tests from the terminal:
# Compile tests with JUnit in classpath
javac -cp ".:lib/junit-4.13.2.jar:lib/hamcrest-core-1.3.jar" test/com/example/myapp/HelloWorldTest.java
# Run tests
java -cp ".:bin:lib/junit-4.13.2.jar:lib/hamcrest-core-1.3.jar" org.junit.runner.JUnitCore com.example.myapp.HelloWorldTest
Following these best practices will help you maintain clean, well-organized projects and streamline your development workflow.