What is Java classpath?

Have you ever read a tutorial, or someone in a forum, or in Discord, say "make sure it's on the classpath" and don't have the foggiest idea what they are talking about? Well it's your lucky day because we are going to figure out what the mysterious Java classpath is.

There is a TLDR at the bottom, if you'd like the concise answer

How the terminal finds and runs programs

First of all, you are going to be running a lot of your Java programs from a terminal. You've probably already used a number of commands in the terminal already, one such example is -

D:\Coding\Dev\Classpath example demo>echo Hello, World
Hello, world

What is happening here? We're using a program called echo to print the line of text "Hello, World". We are calling the program by typing its name then some text, but how does the computer know we have a program called "echo" and how does it find it? There is something called an environment variable which stores a semi-colon separated list of paths to programs, one is aptly called Path.

Lets have a look at my Path using echo

D:\Coding\Dev\Classpath example demo>echo %Path%
C:\Python38\Scripts\;C:\Python38\;C:\Program Files\Java\jdk-13.0.2\bin;
C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\ProgramData\Oracle\Java\javapath;
C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;
...
C:\Program Files\Java\jdk-13.0.2\bin;
...

Wrapping a string with % symbols identifies it as a variable

I've omitted quite a bit here, but you can see these are directory paths within your computer to the location of a program file. The command terminal will check your Path variable's paths when you type a command and see if it can find a matching program with that name, then it will run the program with any options you added, like the text "Hello, world".

Making and running a simple .java program

So now we know how the computer finds a program, and we can see from the list C:\Program Files\Java\jdk-13.0.2\bin, this is the location of the java program. This is how we run our Java code, lets make a simple program and run it. Let's stick to the old faithful, slightly modified, it will output "Hello, world, from Main class" to the terminal.

public class Main {
    public static main(String[] args) {
        System.out.println("Hello, world, from Main class");
    }
}

Now we have a program, lets use java to run it.

D:\Coding\Dev\Classpath example demo>java Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main

Huh, something went wrong. It seems java couldn't find our class called "Main". Well, there's a hint in the error, java is looking for a .class file. A class file is a compiled version of our .java file, which the computer can understand and execute. If we look at the documentation for java (always a good idea to read the doc's!) we can see that the structure for a command is java [options] classname [args]. So how do we get a .class file? We can use another program called javac.

javac, short for Java Compiler, will compile your .java into a .class file. Lets give it a go.

D:\Coding\Dev\Classpath example demo>javac Main.java
D:\Coding\Dev\Classpath example demo>dir
 Volume in drive D is Data
 Volume Serial Number is 64F6-4376

 Directory of D:\Coding\Dev\Classpath example demo

26/05/2021  15:42    <DIR>          .
26/05/2021  15:42    <DIR>          ..
26/05/2021  15:42               414 Main.class
26/05/2021  14:07               162 Main.java
               2 File(s)            576 bytes
               2 Dir(s)  320,053,022,720 bytes free

dir - lists out all the folders and files in the current directory

You can see here there is a new file created Main.class. We can now run this file with java.

D:\Coding\Dev\Classpath example demo>java Main
Hello, world, from Main class

Complicating matters

So this is great. What's the issue with "classpath" then? Lets move our Main.class and try again to run the program.

D:\Coding\Dev\Classpath example demo>mkdir SubFolder

D:\Coding\Dev\Classpath example demo>move Main.class SubFolder
        1 file(s) moved.

D:\Coding\Dev\Classpath example demo>tree /F
Folder PATH listing for volume Data
Volume serial number is 64F6-4376
D:.
│   Main.java
└───SubFolder
        Main.class

tree /F prints a folder and file hierarchy to the console

Here we have created a new sub-folder called "SubFolder" and placed Main.class within. Running the program as before, this happens -

D:\Coding\Dev\Classpath example demo>java Main
Error: Could not find or load main class Main    
Caused by: java.lang.ClassNotFoundException: Main

We've lost our Main.class! So how do we tell java where it is? We put it on the classpath! Lets do that -

D:\Coding\Dev\Classpath example demo>java -cp ./SubFolder Main 
Hello, world, from Main class

. before /SubFolder means the path is relative to where we
are in the file system

What we just did is set the classpath with the -cp option. This tells the JVM where to find the .class file, and it now runs!

A more "real world" example

Ok, so everything is great, right? Well, right now. In real applications there is a lot of classes and a lot of dependencies. Dependencies are code files which your code depends on, and are usually kept in a library of related files you download and add to your project. These are normally kept outside of your project file structure, usually in a some type of container like a .jar file. So, lets look at a practical example, when a class is out in another folder on it's on, simulating being a dependency.

First we will create our new java file and update Main.java with some code that utilises the new class -

public class ExternalClazz {

    public void printText() {
        System.out.println("Hi from elsewhere");
    } 
}
public class Main {

    public static void main(String[] args) {
        System.out.println("Hello, world, from Main class");

        ExternalClazz externalClazz = new ExternalClazz();
        externalClazz.printText();
    }
}

and compile it, along with Main.java to update that code -

javac ExternalClazz.java
javac Main.java

In fact we could have just used javac Main.java, and it would
have compiled both files, as it will parse through Main.java
and discover it needs to compile ExternalClazz.java for
Main.java to work correctly

This creates ExternalClazz.class in our current directory. We can add it to a .jar file and move it to "Dependency" folder -

D:\Coding\Dev\Classpath example demo>jar cvf MyJar.jar ExternalClazz.class
added manifest
adding: ExternalClazz.class(in = 417) (out= 292)(deflated 29%)

D:\Coding\Dev\Classpath example demo>move MyJar.jar Dependency
        1 file(s) moved.

Now the file structure looks like this -

D:.
│   ExternalClazz.java
│   Main.java
├───Dependency
│       MyJar.jar
└───SubFolder
        Main.class

So now we have our Main.class in a sub-folder, and our main method has some code which is dependent on a .class which is in a .jar file, also in another folder. How do we run this?

D:\Coding\Dev\Classpath example demo>java -cp ./Dependency/MyJar.jar;./SubFolder Main
Hello, world, from Main class
Hi from elsewhere

We have used the argument -cp to define the classpath, but this time we've used multiple paths. One points to the .jar file, and the other to where our Main.class is. Does this remind you of anything? That's right, it's the same as the Path environment variable, a list of ; separated paths to target locations.

Developer tools

Now, generally we all use IDEs to make our projects, like InteliJ IDEA, VSCode or Eclipse. Normally these integrated development environments will handle setting the classpath and running the programming, but this is still good knowledge to have and understand.

Here in InteliJ IDEA is where the classpath is set for your project, in run/debug configurations, "Use classpath of module" -
Setting classpath in InteliJ IDEA

and in VSCode, after installing the Java extension -
Setting classpath in VSCode

IDEs are very powerful tools and handle a lot of the under the bonnet configuration, but should we ever run into issues with these configs we'll already be prepared. There are other tools called "build" tools such as Maven and Gradle, which handle pointing JVM to the right places, which is totally out of the scope of this blog post, but they are incredibly useful and you should spend some time to learn them, too.

TLDR;

The Java classpath is a collection of folder or file paths that tell the Java Virtual Machine where the compiled code is which is to be executed in your program. When it can't find the .class files your program cannot run, as the JVM can't find it's instructions. "Putting it on the classpath" means making sure compiled java files are in a folder the classpath knows. Otherwise, you will need to specify that folder when you run your java program. Classpath will check the current folder by default, if it can't find the .class files you need to specify the path with the -cp or -classpath argument, more than one path can be separated with a ;. You can point to .class files or .jar files.

I hope this is helpful, please let me know if I missed anything 😃

Header image photo by Alexander Schimmeck on Unsplash

18