Monday 15 January 2018

java - What does "Could not find or load main class" mean?

itemprop="text">

A common problem that new Java
developers experience is that their programs fail to run with the error message:
Could not find or load main class
...



What does this mean, what
causes it, and how should you fix it?




Answer




The java
command
syntax



First of all, you need to understand the
correct way to launch a program using the java (or
javaw) command.



The
normal syntax1 is
this:



 java [ 



where
is a command line option (starting with a "-"
character), is a fully qualified Java class
name, and is an arbitrary command line
argument that gets passed to your application.
1 - There is a
second syntax for "executable" JAR files which I will describe at the
bottom.



The fully qualified name
(FQN) for the class is conventionally written as you would in Java source code;
e.g.




packagename.packagename2.packagename3.ClassName


However
some versions of the java command allow you to use slashes
instead of periods; e.g.




packagename/packagename2/packagename3/ClassName



which
(confusingly) looks like a file pathname, but isn't one. Note that the term
fully qualified name is standard Java terminology ... not something
I just made up to confuse you :-)



Here is an
example of what a java command should look
like:



 java -Xmx100m
com.acme.example.ListUsers fred joe
bert


The above is
going to cause the java command to do the
following:





  1. Search
    for the compiled version of the com.acme.example.ListUsers
    class.

  2. Load the
    class.

  3. Check that the class has a
    main method with signature,
    return type and modifiers given by
    public static void main(String[]). (Note, the method argument's
    name is NOT part of the
    signature.)

  4. Call that method passing it the command line
    arguments ("fred", "joe", "bert") as a
    String[].



Reasons
why Java cannot find the class




When
you get the message "Could not find or load main class ...", that means that the first
step has failed. The java command was not able to find the
class. And indeed, the "..." in the message will be the fully qualified class
name
that java is looking for.



So why might it be unable to find the class?



Reason #1 - you made a mistake with the
classname argument



The first likely cause is
that you may have provided the wrong class name. (Or ... the right class name, but in
the wrong form.) Considering the example above, here are a variety of
wrong ways to specify the class
name:




  • Example #1
    - a simple class
    name:




    java
    ListUser


    When the
    class is declared in a package such as com.acme.example, then
    you must use the full classname including the package name in the
    java command; e.g.



    java
    com.acme.example.ListUser

  • Example
    #2 - a filename or pathname rather than a class
    name:




    java
    ListUser.class
    java
    com/acme/example/ListUser.class

  • Example
    #3 - a class name with the casing
    incorrect:



    java
    com.acme.example.listuser

  • Example
    #4 - a typo



    java
    com.acme.example.mistuser


  • Example
    #5 - a source filename



    java
    ListUser.java

  • Example
    #6 - you forgot the class name
    entirely



    java lots of
    arguments




Reason
#2 - the application's classpath is incorrectly
specified



The second likely cause is that the
class name is correct, but that the java command cannot find
the class. To understand this, you need to understand the concept of the "classpath".
This is explained well by the Oracle
documentation:





So ... if
you have specified the class name correctly, the next thing to check is that you have
specified the classpath
correctly:





  1. Read
    the three documents linked above. (Yes ... READ them. It is important that a Java
    programmer understands at least the basics of how the Java
    classpath mechanisms works.)

  2. Look at command line and /
    or the CLASSPATH environment variable that is in effect when you run the
    java command. Check that the directory names and JAR file names
    are correct.

  3. If there are relative
    pathnames in the classpath, check that they resolve correctly ... from the current
    directory that is in effect when you run the java
    command.

  4. Check that the class (mentioned in the error
    message) can be located on the effective
    classpath.

  5. Note that the classpath syntax is
    different for Windows versus Linux and Mac OS. (The classpath
    separator is ; on Windows and : on the
    others. If you use the wrong separator for your platform, you won't get an explicit
    error message. Instead, you will get a nonexistent file or directory on the path that
    will be silently
    ignored.)



Reason #2a -
the wrong directory is on the classpath



When
you put a directory on the classpath, it notionally corresponds to the root of the
qualified name space. Classes are located in the directory structure beneath that root,
by mapping the fully qualified name to a pathname. So for example,
if "/usr/local/acme/classes" is on the class path, then when the JVM looks for a class
called com.acme.example.Foon, it will look for a ".class" file
with this pathname:





/usr/local/acme/classes/com/acme/example/Foon.class


If
you had put "/usr/local/acme/classes/com/acme/example" on the classpath, then the JVM
wouldn't be able to find the class.



Reason #2b
- the subdirectory path doesn't match the
FQN



If your classes FQN is
com.acme.example.Foon, then the JVM is going to look for
"Foon.class" in the directory
"com/acme/example":





  • If
    your directory structure doesn't match the package naming as per the pattern above, the
    JVM won't find your class.


  • If you
    attempt rename a class by moving it, that will fail as well ... but
    the exception stacktrace will be different. It is liable to say something like
    this:



    Caused by:
    java.lang.NoClassDefFoundError: (wrong name:
    )


    because
    the FQN in the class file doesn't match what the class loader is expecting to
    find.





To
give a concrete example, supposing
that:




  • you want to run
    com.acme.example.Foon class,

  • the
    full file path is
    /usr/local/acme/classes/com/acme/example/Foon.class,

  • your
    current working directory is
    /usr/local/acme/classes/com/acme/example/,



then:




class="lang-bash prettyprint-override"># wrong, FQN is
needed
java Foon

# wrong, there is no `com/acme/example`
folder in the current working directory
java
com.acme.example.Foon

# wrong, similar to above
java
-classpath . com.acme.example.Foon

# fine; relative classpath
set

java -classpath ../../..
com.acme.example.Foon

# fine; absolute classpath set
java
-classpath /usr/local/acme/classes
com.acme.example.Foon


Notes:




  • The
    -classpath option can be shortened to
    -cp in most Java releases. Check the respective manual entries
    for java, javac and so
    on.


  • Think carefully when choosing between
    absolute and relative pathnames in classpaths. Remember that a relative pathname may
    "break" if the current directory changes.



Reason #2c -
dependencies missing from the classpath



The
classpath needs to include all of the other (non-system) classes
that your application depends on. (The system classes are located automatically, and you
rarely need to concern yourself with this.) For the main class to load correctly, the
JVM needs to find:





(Note:
the JLS and JVM specifications allow some scope for a JVM to load classes "lazily", and
this can affect when a classloader exception is
thrown.)




Reason #3 - the class has
been declared in the wrong package



It
occasionally happens that someone puts a source code file into the
the wrong
folder in their source code tree, or they leave out the package
declaration. If you do this in an IDE, the IDE's compiler will tell you about this
immediately. Similarly if you use a decent Java build tool, the tool will run
javac in a way that will detect the problem. However, if you
build your Java code by hand, you can do it in such a way that the compiler doesn't
notice the problem, and the resulting ".class" file is not in the place that you expect
it to be.



Still can't find the
problem?



There lots of things to check, and it
is easy to miss something. Try adding the -Xdiag option to the
java command line (as the first thing after
java). It will output various things about class loading, and
this may offer you clues as to what the real problem
is.




Also, consider possible problems
caused by copying and pasting invisible or non-ASCII characters from websites, documents
and so on. And consider "homoglyphs", were two letters or symbols look the same ... but
aren't.






The
java -jar
syntax



The alternative syntax used for
"executable" JAR files is as
follows:



 java [ 



e.g.




java -Xmx100m -jar /usr/local/acme-example/listuser.jar
fred


In this case the
name of the entry-point class (i.e. com.acme.example.ListUser)
and the classpath are specified in the MANIFEST of the JAR
file.



/>


IDEs



A
typical Java IDE has support for running Java applications in the IDE JVM itself or in a
child JVM. These are generally immune from this particular
exception, because the IDE uses its own mechanisms to construct the runtime classpath,
identify the main class and create the java command
line.



However it is still possible for this
exception to occur, if you do things behind the back of the IDE. For example, if you
have previously set up an Application Launcher for your Java app in Eclipse, and you
then moved the JAR file containing the "main" class to a different place in the file
system without telling Eclipse, Eclipse would unwittingly launch
the JVM with an incorrect classpath.



In short,
if you get this problem in an IDE, check for things like stale IDE state, broken project
references or broken launcher configurations.



It
is also possible for an IDE to simply get confused. IDE's are hugely complicated pieces
of software comprising many interacting parts. Many of these parts adopt various caching
strategies in order to make the IDE as a whole responsive. These can sometimes go wrong,
and one possible symptom is problems when launching applications. If you suspect this
could be happening, it is worth trying things lie restarting your IDE and rebuilding the
project.




/>

Other
References




No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...