Search code examples
javaclasspathjavac

Java: Error: Could not find or load main class Hello when trying to import an external library


I know it's a common question, but I have read all the other answers and couldn't find a solution. I am trying to understand the Java classpath, but I run into the Error: Could not find or load main class Hello when I try to specify an external library.

I started with this simple program, which resides directly in my home directory:

import java.util.*;

public class Hello {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println("Hello world");
    }
}

This compiles and runs just fine...

[user ~]> ls -l
Hello.java
[user ~]> javac Hello.java
[user ~]> ls -l
Hello.java
Hello.class
[user ~]> java Hello
Hello world

...which tells me that the classpath environment variable is set correctly (because it finds the java.util package).

Yet when I try to import a random 3rd party package and specify its location in the -classpathI get the error:

[user ~]> cat Hello.java
import java.util.*;
import org.apache.commons.lang3.time.*;

public class Hello {
    public static void main(String[] args) {
        StopWatch sw = new StopWatch();
        Date date = new Date();
        System.out.println("Hello world");
    }
}
[user ~]> ls .m2/repository/org/apache/commons/commons-lang3/3.3.1
commons-lang3-3.3.1.jar
[user ~]> javac -classpath ~/.m2/repository/org/apache/commons/commons-lang3/3.3.1/commons-lang3-3.3.1.jar Hello.java
[user ~]> java -classpath ~/.m2/repository/org/apache/commons/commons-lang3/3.3.1/commons-lang3-3.3.1.jar Hello
Error: Could not find or load main class Hello

Could someone give me an idea what I'm doing wrong here?


Solution

  • First, java.util classes are part of the JRE itself, and are thus automatically available, whatever the classpath is.

    The first example works fine because you're not specifying any classpath, and the default one (which is just ., i.e. the current directory) is thus used.

    The second example specifies a classpath, but doesn't include . (the current directory) in it, so the commons-lang classes are available at runtime, but not your Hello class. Use

    java -classpath .:~/.m2/repository/org/apache/commons/commons-lang3/3.3.1/commons-lang3-3.3.1.jar Hello
    

    Also, in the future:

    • don't ever, ever put a class in the default package
    • create a real project structure, containing
      • a root directory
      • a source directory containing the .java files, properly organized in a package structure
      • a classes directory, containing the compiled .class files, that you can just clear when you want to recompile everything from scratch

    The next step would of course to use Gradle or Maven as a build tool, and follow their recommended project layout.