A badly configured environment is the number one reason people give up on learning Java. The error messages are cryptic ('javac' is not recognized as a command, JAVA_HOME is not set, UnsupportedClassVersionError) and have nothing to do with programming. This lesson removes that obstacle once and for all: you will install a JDK, check that it works, understand why JAVA_HOME and PATH exist instead of just copying commands, compile and run your first program from the terminal, and choose the IDE you will work with for the whole course. By the end you will have the bibliotech project created and ready for you to write code.

Contents

  1. Which JDK to choose and where to download it
  2. Installing on Windows, macOS and Linux
  3. Verifying the installation: java -version and javac -version
  4. JAVA_HOME and PATH: what they are and how to configure them
  5. Your first program from the terminal: HelloBiblioTech.java
  6. JShell: the laboratory for learning
  7. Choosing an IDE and creating the bibliotech project
  8. Recommended folder structure
  9. Common Mistakes and Tips
  10. Exercises

  1. Which JDK to choose and where to download it

The previous lesson made it clear that you need a JDK (not a JRE), because the JDK includes the javac compiler. What you may not have expected is that there are several different JDKs for the same Java version.

They all start from the same source code, OpenJDK, which is the open-source reference implementation. What changes between distributions is who builds it, who signs it, for how long they publish patches and under which licence.

Distribution Who publishes it Licence and cost Recommendation
Eclipse Temurin Eclipse Adoptium Free (GPL+CE), free in production too The course's recommended option
Oracle JDK Oracle Free for development; specific terms in production Valid, but check the licence if it is for a company
Amazon Corretto Amazon Free, long support Good if you deploy on AWS
Azul Zulu Azul Systems Free, with optional commercial support A good alternative
Microsoft Build of OpenJDK Microsoft Free Good if you work on Azure

Practical recommendation: download Eclipse Temurin 21 (or 17 if you prefer to stick strictly to the course's minimum version) from adoptium.net. It is free with no strings attached, widely used in production and requires no user account to download.

About the version: this course uses Java 17 as its reference and explicitly flags anything that needs a higher version. If you install Java 21, everything will work the same and you will also have the most recent improvements available. Both are LTS.

One detail when downloading: pick the right package for your processor. On Windows and most Linux PCs it will be x64. On a modern Mac (M1, M2, M3, M4) it will be aarch64/ARM64; on an older Mac, x64. Downloading the wrong binary causes baffling startup errors.

  1. Installing on Windows, macOS and Linux

Windows

  1. On adoptium.net, download the Temurin .msi installer for Windows x64, version 21 (LTS), JDK (not JRE).
  2. Run the installer. On the custom options screen, tick these two boxes, which will save you the whole of section 4:
    • Add to PATH
    • Set JAVA_HOME variable
  3. Finish the installation. The JDK will normally end up in C:\Program Files\Eclipse Adoptium\jdk-21.x.x-hotspot.
  4. Open a new terminal (PowerShell or Command Prompt). This step is mandatory: terminals that are already open cannot see the new environment variables.

macOS

The most convenient way is Homebrew. If you do not have it, install it from brew.sh. Then:

# Install Temurin 21
brew install --cask temurin@21

# Check which JDK the system has detected
/usr/libexec/java_home -V

If you would rather not use Homebrew, download the .pkg installer from Adoptium and run it; the JDK will be installed under /Library/Java/JavaVirtualMachines/.

macOS ships a very handy utility, /usr/libexec/java_home, which locates the installed JDK. You will use it in section 4.

Linux

On Debian- or Ubuntu-based distributions, the package from the official repositories is usually enough:

sudo apt update
sudo apt install openjdk-21-jdk

On Fedora or RHEL:

sudo dnf install java-21-openjdk-devel

Watch the suffixes: on Debian/Ubuntu the -jdk package includes the compiler, and on Fedora it is the -devel suffix. If you install openjdk-21-jre or plain java-21-openjdk, you will have a JVM but no javac.

If your distribution does not offer the version you want, download the .tar.gz from Adoptium and unpack it under /opt:

sudo mkdir -p /opt/java
sudo tar -xzf OpenJDK21U-jdk_x64_linux_hotspot_21.tar.gz -C /opt/java

A note for anyone juggling several versions: tools such as SDKMAN! (sdkman.io) let you install and switch between JDKs with a single command (sdk install java 21-tem, sdk use java 17-tem). It is what many people who work with projects of different ages use. It is not required for the course, but it is worth knowing about.

  1. Verifying the installation: java -version and javac -version

This is the moment of truth. Open a new terminal and run both commands:

java -version
javac -version

Correct output looks something like this (the exact numbers will vary):

openjdk version "21.0.5" 2024-10-15 LTS
OpenJDK Runtime Environment Temurin-21.0.5+11 (build 21.0.5+11-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.5+11 (build 21.0.5+11-LTS, mixed mode, sharing)

javac 21.0.5

Let's interpret what each command is telling you:

  • java -version shows the version of the JVM that will run. If this command responds, you can run Java programs.
  • javac -version shows the version of the compiler. If this command fails but the previous one works, you have a JRE or an incomplete installation: you will not be able to compile.

It is essential that both numbers match. On machines where several JDKs have been installed over time it is very common to find a java from version 8 and a javac from version 21. In that scenario you compile modern code that your JVM refuses to run, and the dreaded UnsupportedClassVersionError shows up.

If either command answers with "is not recognized as an internal or external command" (Windows) or "command not found" (macOS/Linux), the JDK is installed but the system does not know where to find it. That is exactly what the next section solves.

  1. JAVA_HOME and PATH: what they are and how to configure them

What they really are

They are two environment variables: text values that the operating system makes available to every program it starts.

  • PATH is a list of directories separated by ; (Windows) or : (macOS/Linux). When you type javac in the terminal, the system walks that list in order looking for an executable with that name and runs the first one it finds. If your JDK's bin directory is not on the PATH, the terminal cannot find javac even though it is perfectly installed. And if there are two JDKs on the PATH, the one that appears first wins: that is the usual cause of mismatched versions.

  • JAVA_HOME points to the JDK's root folder (the one containing bin, lib, conf…), not to an executable. It is not used by the terminal but by other tools: Maven, Gradle, application servers, startup scripts and some IDEs read it to know which JDK they should work with. You can have Java working in the terminal without JAVA_HOME, but as soon as you use a tool from the ecosystem it will ask for it.

flowchart LR
    A["You type<br/>javac Hello.java"] --> B["The system walks PATH<br/>directory by directory"]
    B --> C{"Does it find<br/>javac?"}
    C -->|"Yes"| D["It runs it<br/>(the first on the list)"]
    C -->|"No"| E["command not found"]
    F["Maven, Gradle,<br/>servers…"] --> G["They read JAVA_HOME<br/>to locate the JDK"]

Windows

  1. Press the Windows key and search for "Edit the system environment variables".
  2. Click Environment Variables….
  3. Under System variables, click New:
    • Name: JAVA_HOME
    • Value: the JDK's root path, for example C:\Program Files\Eclipse Adoptium\jdk-21.0.5.11-hotspot
  4. Select the Path variable, click Edit and add a new entry: %JAVA_HOME%\bin. Using %JAVA_HOME% instead of the full path is good practice: the day you upgrade the JDK, you will only have to change JAVA_HOME.
  5. If there are old entries from other Java installations (for example C:\ProgramData\Oracle\Java\javapath), move them below yours or delete them.
  6. Accept everything and open a new terminal.

To check it:

echo %JAVA_HOME%
where java

In PowerShell they would be $env:JAVA_HOME and Get-Command java.

macOS and Linux

The configuration goes in your shell's startup file: ~/.zshrc if you use zsh (the default on modern macOS) or ~/.bashrc / ~/.bash_profile if you use bash. Add at the end:

On macOS:

export JAVA_HOME=$(/usr/libexec/java_home -v 21)
export PATH="$JAVA_HOME/bin:$PATH"

On Linux (adjust the path to your actual installation):

export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"

Note the detail in PATH="$JAVA_HOME/bin:$PATH": we put our bin in front of the existing PATH, so that it wins over any other installed Java. Then reload the configuration:

source ~/.zshrc     # or ~/.bashrc
java -version
echo $JAVA_HOME
which java

On Linux, if you have several versions installed through the package manager, the sudo update-alternatives --config java command lets you choose which one is the system default.

  1. Your first program from the terminal: HelloBiblioTech.java

You are going to compile and run a program without an IDE. Even if you later always work with IntelliJ or Eclipse, doing it by hand once is what turns "compiling" into something concrete instead of a magic button.

Create a working folder and, inside it, a file named exactly HelloBiblioTech.java:

public class HelloBiblioTech {
    public static void main(String[] args) {
        System.out.println("BiblioTech - Nexus Software");
        System.out.println("Internal technical library management system");
        System.out.println("Version 0.1");
    }
}

We are not going to dissect this structure yet (that is lesson 01-03), but there is one rule you need right now: the file name must match the name of the public class, capital letters included. The class is called HelloBiblioTech, so the file is HelloBiblioTech.java. If you save it as hellobibliotech.java or Hello.java, the compiler will reject it with a message like "class HelloBiblioTech is public, should be declared in a file named HelloBiblioTech.java".

Compiling and running

# 1. Compile: generates HelloBiblioTech.class
javac HelloBiblioTech.java

# 2. Check that the .class was created
ls          # on Windows: dir

# 3. Run: CAREFUL, WITHOUT the .class extension
java HelloBiblioTech

Expected output:

BiblioTech - Nexus Software
Internal technical library management system
Version 0.1

Both commands deserve a detailed explanation:

  • javac HelloBiblioTech.java takes the file name with its extension. It translates the source into bytecode and creates HelloBiblioTech.class in the same directory. If there are no errors it prints nothing: in command-line tools, silence means success.
  • java HelloBiblioTech takes the class name, without an extension and without .class. This is where almost everybody gets it wrong the first time by typing java HelloBiblioTech.class, which produces a "class not found" error. The reason is conceptual: java does not open a file, it loads a class by name, looking for it on the classpath (by default, the current directory).

Running the source directly (Java 11 and above)

Since Java 11 there is a very convenient shortcut for single-file programs:

java HelloBiblioTech.java

Notice that here it does carry the .java extension. This mode compiles the file in memory and runs it on the fly, leaving no .class on disk. It is perfect for quick tests and for learning, but it has limits: it only works for programs contained in a single source file. As soon as your project has several classes (from module 3 onwards), you will go back to javac or, more likely, let the IDE do it for you.

Command Extension What it does When to use it
javac File.java yes, .java Compiles and generates a .class Whenever you want the bytecode
java ClassName no Runs an already compiled class Normal execution
java File.java yes, .java Compiles in memory and runs Quick single-file tests (Java 11+)

  1. JShell: the laboratory for learning

Java 9 introduced JShell, an interactive console (what other languages call a REPL: read-eval-print loop). It lets you write standalone expressions and see the result instantly, without creating a file, without a class and without a main.

jshell

A typical session:

jshell> int daysLate = 12
daysLate ==> 12

jshell> double dailyRate = 0.25
dailyRate ==> 0.25

jshell> double fine = daysLate * dailyRate
fine ==> 3.0

jshell> String title = "Effective Java"
title ==> "Effective Java"

jshell> title.toUpperCase()
$5 ==> "EFFECTIVE JAVA"

jshell> title.length()
$6 ==> 14

jshell> /exit
|  Goodbye

Notice a couple of details:

  • Semicolons at the end of each line are not required (although you may write them).
  • When an expression is not stored in a variable, JShell assigns it an automatic name ($5, $6) that you can reuse afterwards.

JShell commands start with a slash:

Command Purpose
/vars Lists the variables defined in the session
/list Shows all the code you have written
/imports Shows the active imports
/help Full help
/exit Quit

What it will be useful for during the course: every time you are unsure how something behaves ("what exactly does 5/2 return?", "does trim() also remove tabs?"), opening JShell and testing it in five seconds is infinitely better than guessing. Use it freely in modules 1, 4 and 5.

  1. Choosing an IDE and creating the bibliotech project

An IDE (Integrated Development Environment) is an editor that also compiles, runs, debugs, autocompletes and spots errors as you type. In Java it is practically essential: the professional ecosystem assumes it.

IDE Cost Strengths Weaknesses Recommended for
IntelliJ IDEA Community Free (Apache 2.0) The best autocompletion and refactoring; excellent debugger; very polished Uses quite a lot of memory; the free version does not include advanced web/Spring support The course's recommended option
Eclipse IDE Free Highly extensible; very fast incremental compiler; standard in many companies Less modern interface; the initial setup can be confusing Anyone working at companies that already use it
Visual Studio Code Free Lightweight; multi-language; instant startup Needs the Extension Pack for Java; less powerful for large refactorings Anyone already using VS Code for other languages
NetBeans Free Everything integrated out of the box Smaller community Occasional use

For this course the recommendation is IntelliJ IDEA Community Edition: its real-time error detection and its suggestions are, in practice, an invisible teacher correcting you as you type. That said, any of the four will do; the course code is identical in all of them.

Creating the project in IntelliJ IDEA Community

  1. Open IntelliJ and click New Project.
  2. Fill in:
    • Name: bibliotech
    • Location: the folder where you keep your projects
    • Language: Java
    • Build system: IntelliJ (do not pick Maven or Gradle yet; we will see them in module 11)
    • JDK: select the 21 (or 17) you installed. If it does not appear, use Add JDK… and browse to the JAVA_HOME folder.
    • Untick Add sample code so you start from scratch.
  3. Click Create.
  4. In the left-hand panel, right-click the src folder → NewJava Class and type HelloBiblioTech.
  5. Paste the code from section 5 and click the green triangle in the margin to run it. You will see the output in the Run window.

In Eclipse

FileNewJava Project, name bibliotech, select JRE/JDK 21 and untick the creation of module-info.java. Then right-click srcNewClass, name HelloBiblioTech, and tick the box that generates the main method.

In VS Code

Install Microsoft's Extension Pack for Java. Then Ctrl+Shift+PJava: Create Java ProjectNo build tools → choose a folder and the name bibliotech.

  1. Recommended folder structure

Even though in this module you work with one or two files, it is worth adopting the standard Java-world structure right away. It is the one Maven expects (module 11), the one every IDE recognises and the one you will see in any professional project:

bibliotech/
├── src/
│   └── main/
│       ├── java/                      <- .java source code
│       │   └── com/
│       │       └── nexussoftware/
│       │           └── bibliotech/
│       │               └── BiblioTechApp.java
│       └── resources/                 <- data and configuration files
├── src/
│   └── test/
│       └── java/                      <- automated tests (module 11)
├── out/  (or target/)                 <- generated .class files
└── README.md

Three important ideas about this structure:

  • Source code and compiled code live in separate folders. Never mix .java and .class in the same place in a real project: the output folder is deleted and regenerated constantly, and it is not kept in version control.
  • The com/nexussoftware/bibliotech directories mirror the package com.nexussoftware.bibliotech. In Java, the package hierarchy must match the folder hierarchy. We will explain it in detail in the next lesson; for now, just remember that it is not decorative.
  • Separate src/main and src/test anticipate the arrival of automated tests.

About build tools: Maven and Gradle automate compilation, dependency management and packaging. They are indispensable in any real project and we will devote the whole of lesson 11-05 to them. You do not need them in this module: adding them now would only put noise between you and the language.

Common Mistakes and Tips

  • 'javac' is not recognized as a command. The JDK's bin directory is not on the PATH, or you installed a JRE. Review section 4 and remember to open a new terminal after touching environment variables.
  • java -version and javac -version show different versions. You have more than one Java installed and the PATH is mixing them. Run where java / where javac (Windows) or which -a java javac (Unix) to see every active path and put the JDK you want at the start of the PATH.
  • Error: Could not find or load main class HelloBiblioTech.class. You typed java HelloBiblioTech.class. The java command takes the class name, without an extension.
  • class X is public, should be declared in a file named X.java. The file name does not match the public class name. Java is case-sensitive here too.
  • UnsupportedClassVersionError: ... has been compiled by a more recent version of the Java Runtime. You compiled with a JDK newer than the JVM you are running on. Unify the versions, or compile with javac --release 17.
  • Not seeing the real file extensions on Windows. File Explorer hides known extensions by default, and you end up with HelloBiblioTech.java.txt. Turn on View → File name extensions before going any further.
  • Tip: keep your projects in a path without spaces or accented characters (C:\dev\bibliotech, not C:\My Documents\Programming\). Many tools in the Java ecosystem still have trouble with such paths.
  • Tip: spend fifteen minutes learning three shortcuts in your IDE: run the program, find a class by name, and rename an identifier across the whole project. It is the best time investment of the course.

Exercises

Exercise 1: Auditing your environment

Carry out a full check of your installation and note down the results:

  1. The version reported by java -version and javac -version. Do they match?
  2. The value of JAVA_HOME.
  3. The physical path of the java executable being used.
  4. Is there more than one Java installed on your machine?

Write the exact commands you would use on your operating system and explain what each result tells you.

Exercise 2: Compiling the BiblioTech card by hand

Without using the IDE, create in a folder called tests a file BookCard.java that prints the card for the book "Effective Java" to the console in exactly this format:

=== BiblioTech: book card ===
Title: Effective Java
ISBN: 978-0000000001
Status: available

Compile it and run it with javac and java. Then run it with the Java 11+ single-file mode. Answer: what difference do you see in the folder contents after each method?

Exercise 3: Exploring with JShell

Open JShell and, without writing any file, calculate the fine for a BiblioTech loan: define a variable daysLate with value 9, a constant dailyRate with value 0.25 and calculate the fine. Then use /vars to list what you have defined. Finally, try typing title.length() on a title variable you have not defined and look at the error message.

Solutions

Solution 1

On Windows (PowerShell):

java -version
javac -version
$env:JAVA_HOME
Get-Command java | Select-Object Source
where.exe java

On macOS / Linux:

java -version
javac -version
echo $JAVA_HOME
which java
which -a java javac      # shows ALL the matches on the PATH

Interpreting the results:

  • If java -version and javac -version give the same major number (for example, both 21), your environment is consistent and you can compile and run without surprises.
  • JAVA_HOME must point to the JDK's root folder. If it points to .../bin or is empty, tools like Maven will fail later on.
  • which -a java (or where.exe java) is the key to this exercise: if it returns more than one line, you have several Java installations and the one in charge is the one on the first line. That is where most version inconsistencies come from.

Solution 2

The BookCard.java file:

public class BookCard {
    public static void main(String[] args) {
        // Each println prints its text and moves to the next line.
        System.out.println("=== BiblioTech: book card ===");
        System.out.println("Title: Effective Java");
        System.out.println("ISBN: 978-0000000001");
        System.out.println("Status: available");
    }
}

Classic compilation and execution:

javac BookCard.java
java BookCard

Running the source directly:

java BookCard.java

Observable difference: after javac, the folder contains two files: BookCard.java and BookCard.class. After running the source directly, there is still only BookCard.java: the compilation happens in memory and the bytecode is discarded when the program ends. That is why the direct mode is handy for testing but useless for distribution: it produces nothing you can hand over.

Solution 3

jshell> int daysLate = 9
daysLate ==> 9

jshell> final double dailyRate = 0.25
dailyRate ==> 0.25

jshell> double fine = daysLate * dailyRate
fine ==> 2.25

jshell> /vars
|    int daysLate = 9
|    double dailyRate = 0.25
|    double fine = 2.25

jshell> title.length()
|  Error:
|  cannot find symbol
|    symbol:   variable title
|  title.length()
|  ^---^

Two observations worth internalising right now:

  • The result 2.25 comes from multiplying an int by a double: Java automatically converts the integer to a decimal before operating. It is a widening conversion, and you will study it formally in lesson 01-04.
  • The cannot find symbol error is one of the most frequent messages from the Java compiler and it always means the same thing: you are using a name the compiler does not know. The typical causes are not having declared the variable, having typed it with different capitalisation, or having declared it in a different scope. Learning to recognise it instantly will save you a lot of time.

Conclusion

You now have a working environment: an LTS JDK installed, java and javac responding with the same version, JAVA_HOME and PATH configured and understood, your first HelloBiblioTech program compiled and run from the terminal, JShell available for experimenting and the bibliotech project created in your IDE with the standard folder structure. Everything from here on is programming.

In the next lesson, Basic Syntax and Structure, we will dissect that HelloBiblioTech.java file word by word: what exactly public static void main(String[] args) means, what statements and blocks are, how code is commented, which naming conventions everyone follows in Java and why, how packages work and how they relate to directories, and how to read the compiler's error messages so that you never get stuck.

Java Programming Course

Module 1: Introduction to Java

Module 2: Control Flow

Module 3: Object-Oriented Programming

Module 4: Advanced Object-Oriented Programming

Module 5: Data Structures and Collections

Module 6: Exception Handling

Module 7: File Input/Output

Module 8: Multithreading and Concurrency

Module 9: Networking

Module 10: Advanced Topics

Module 11: Java Frameworks and Libraries

Module 12: Building Real-World Applications

© Copyright 2026. All rights reserved