Back to the basics of Java — Part 1: Classpath

Ludvig Westerdahl
Javarevisited
Published in
5 min readAug 30, 2021

--

My favourite programming language has always been Java, coincidentally it was also my first language I ever used. If you’re like me, or just wants to learn more about the awesome language & technology that is Java, then this two part series is for you.

In these short series, you will learn about the following.

  • Part 1: Classpath
  • Part 2: The JAR

So, why did I decide to write these articles? Well, there was some aspects of Java I did not fully comprehend (such as the classpath) and I realized the reason for this is because I have been using an IDE and build tools.

The issue with an IDE is that it hides a lot of stuff which hinders a fully comprehensive understanding. In other words, I thought it was time to get a little bit more comfortable with the java cli tools and going back to basics.

Now let’s get down to it. In this part I will explain what the classpath is and how to use it correctly (and incorrectly).

Classpath

The classpath is simply a list of directories, JAR files, and ZIP archives to search for class files [1]. The runtime needs to know where to find your compiled classes so that’s what you’re providing here.

There are some things that you should be aware of though regarding how you specify the paths. To explain this I will create a dummy project, see below for the structure.

ClasspathProject/src/java/myprogram/
|
---> Main.java
|
---> utils/
|
---> Util.java

And here are the source files just so you know what we are dealing with.

Main.java

Util.java

I will be using this structure for the following parts as well so If you want to follow along I suggest you create it as well before proceeding.

A short note on packages.

If you are new to java it can be helpful to know that packages are generally suppose to be mirrored by the file structure. Take the Utils.java file for instance, it has the package myprogram.utils because it is in that folder.

The structure as provided is not really required by the compiler. However, it is required by the java command to run.

Let’s compile this little project.

First we create a bin folder to hold the compiled stuff in the root project folder then compile the two files [2].

> mkdir bin
> javac src/java/myprogram/Main.java src/java/myprogram/utils/Util.java -d bin/

You should now have the following file structure.

ClasspathProject/
|
---> src/java/myprogram/
|
---> Main.java
|
---> utils/
|
---> Util.java
|
---> bin/myprogram/
|
---> Main.class
|
---> utils/
|
---> Util.class

If we now move to the bin folder we can run the main class.

> java myprogram.Main
Here is 1337

Great, so why does this work? Because the default value for the classpath is the current directory. It needs to find two class files; Main.class and Utils.class, how and where does it look? Given the current class path of bin and our main class myprogram.Main it will look in this directory to try and find the following:

  • myprogram/Main.class
  • myprogram/utils/Util.class

Which we know exists, so the program runs successfully.

Now let’s change it up a little bit. Let’s add a new folder lib on the same level as bin and move the Utils.class so that it now looks like this.

ClasspathProject/
|
---> src/java/myprogram/
|
---> Main.java
|
---> utils/
|
---> Util.java
|
---> bin/myprogram/
|
---> Main.class
|
---> lib/myprogram/
|
---> utils/
|
---> Util.class

Error 1— No classpath specified

If we now move to the bin folder and try and run the same command we will get an error because it cant find the Util.class file.

> java myprogram.Main
Exception in thread "main" java.lang.NoClassDefFoundError: myprogram/utils/Util
at myprogram.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: myprogram.utils.Util
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 1 more

Error 2 — Adding a class file to the classpath

We will try and solve this by adding the class file to the classpath (we are running all these commands from the bin folder).

> java -classpath ../lib/myprogram/utils/Util.class myprogram.Main
Error: Could not find or load main class myprogram.Main
Caused by: java.lang.ClassNotFoundException: myprogram.Main

Ouch, now it cannot find the Main.class file? Because as previously explained, it will try and find the files in the specified directories provided in the classpath. And we did not provide a directory. So let’s do that instead.

Error 3 — Adding one directory to the classpath

> java -classpath ../lib/myprogram/utils/ myprogram.Main
Error: Could not find or load main class myprogram.Main
Caused by: java.lang.ClassNotFoundException: myprogram.Main

Okay, same error. What happened here? Since we provided a classpath argument that overrides the default one (which is the current directory) it cannot find our Main.class file anywhere. Let’s add that. On Unix systems you separate with a colon (:) and on Windows, you use a semi-colon (;).

Error 4 — Adding more paths to the classpath

> java -classpath ../lib/myprogram/utils/:. myprogram.Main
Exception in thread "main" java.lang.NoClassDefFoundError: myprogram/utils/Util
at myprogram.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: myprogram.utils.Util
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 1 more

Okey, now it seems that it can find the Main.class file. But it still cannot find the Util.class file. As previously explained it will try and find the following files using any of the classpaths.

  • myprogram/Main.class
  • myprogram/utils/Util.class

In this case we have two classpaths.

  • ../lib/myprogram/utils/
  • .

So simply put, it will try and append the classpaths to the required files to see if they exist, I image the process would look something like this.

Cp1 = ../lib/myprogram/utils/
Cp2 = ./
File1 = myprogram/Main.class
File2 = myprogram/utils/Util.class
Trying to find File1Cp1 + File1 = ../lib/myprogram/utils/myprogram/Main.class
NOT FOUND
Cp2 + File1 = ./myprogram/Main.class
FOUND
Trying to find File2Cp1 + File2 = ../lib/myprogram/utils/myprogram/utils/Util.class
NOT FOUND
Cp2 + File2 = ./myprogram/utils/Util.class
NOT FOUND
---> ERROR

Final solution

Can we solve this by adding those subfolders under lib? Sure we can, which will work. However, instead of adding those folders let’s modify the classpath argument instead so that it looks like this.

> java -classpath ../lib/:. myprogram.Main
Here is 1337

This works because it will now be able to find Utils.class file using the first path.

../lib/ + myprogram/utils/Util.class
FOUND

I hope that some of the errors here have helped your understanding of the class path. It seems that a lot of tutorials only present the correct way of doing things but I find that seeing the incorrect way of doing things helps my learning a lot more.

References

[1] java options
https://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html

[2] javac — Java programming language compiler
https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html

--

--

Ludvig Westerdahl
Javarevisited

I'm a software engineer with a great passion for both software and finance. Hit me up at: https://linkedin.com/in/ludvigwesterdahl