Featured

Compiling and Testing Your First Java Program

In this blog post, we’ll use the Java compiler and interpreter from the command line. The examples are based on Windows.

 

The source code of a Java program can’t be executed in this way alone. A special program, the compiler (also called interpreter), transforms the written program into another representation. In the case of Java, the compiler generates the DNA of each program—the bytecode.

 

A Square Numbers Program

Our first Java program will run a repetition of screen outputs that replicates a song for boring trips. The output should be the following:

 

99 bottles of beer on the wall, 99 bottles of beer. Take one down, pass it around,

98 bottles of beer on the wall, 98 bottles of beer. Take one down, pass it around,

97 bottles of beer on the wall, 97 bottles of beer. Take one down, pass it around,

96 bottles of beer on the wall, 96 bottles of beer. Take one down, pass it around,

[…]

3 bottles of beer on the wall, 3 bottles of beer. Take one down, pass it around,

2 bottles of beer on the wall, 2 bottles of beer. Take one down, pass it around,

1 last bottle of beer on the wall, 1 last bottle of beer.

 

For this example, put the source code in the document folder of the current user %homepath%\Documents (for example, C:\Users\User\Documents). The name of the source code file is NinetyNineBottlesOfBeer.java. Since the source code is pure text, you can create and edit it with any text editor.

 

For Windows users, the Notepad editor can be found under Start > Programs > Accessories > Editor. When saving with Notepad using File > Save as, the File Name field must have NinetyNineBottlesOfBeer.java, and All files (*.*) must be selected in the Save as type field so that the editor doesn’t automatically assign the file extension .txt.

 

/**

* Prints a version of 99 Bottles of Beer

* @version 2.0 18-01-2022

* @author Christian Ullenboom

*/

public class NinetyNineBottlesOfBeer {

   public static void main( String[] args ) {

       for ( int i = 99; i > 1; i-- ) {

           System.out.print( i );

           System.out.print( " bottles of beer on the wall, " );

           System.out.print( i );

           System.out.println( " bottles of beer. Take one down, pass it around," );

       }

           System.out.println( "1 bottle of beer on the wall, 1 bottle of beer." ); 1

       }

}

 

The entire program logic sits in the NinetyNineBottlesOfBeer class, which contains one method. All methods in an OOP language like Java must be placed in classes. A special subroutine called main(String[]) serves as an entry point for the JVM. The main(String[]) method performs a loop and produces the screen outputs.

 

The Compiler Run

Now, let’s change to the command prompt (console) and navigate to the directory with the source code. If the source code file is available, the compiler translates it into bytecode. For our Java class in the NinetyNineBottlesOfBeer.java file, you would use the following path:

 

C:\Users\User\Documents>javac NinetyNineBottlesOfBeer.java

 

Provided that the program was free of errors, the compiler now creates the NinetyNineBottlesOfBeer.class file, which contains the bytecode. When calling javac, the file to be translated must be specified completely, including its file extension. But wildcards are also possible: Thus, javac *.java translates all Java classes in the current directory. Although not important in Windows, case sensitivity should be respected.

 

Compiler Errors: If the compiler finds a syntactical error in a line, the compiler reports the error by specifying the file and the line number. Let’s look at our program again and build in an error in line 9 in the main(...) method (the semicolon falls victim to the delete key).

 

In other words, the initial

 

System.out.print( i );

 

becomes

 

System.out.print( i )

 

The compiler run reports the following error:

 

C:\Users\User\Documents>javac NinetyNineBottlesOfBeer.java

   System.out.print( i )

                        ^

1 error

 

When the compiler can’t perform a translation into Java bytecode due to a syntactic error, we call this a compiler error or a translation error. Even though the term “compiler error” sounds as if the compiler itself has an error, it’s our program that has the error.

 

The Runtime Environment

The bytecode generated by the compiler isn’t common machine code for a specific processor because Java was designed as a platform-independent programming language, so it doesn’t cling to a physical processor—processors like Intel, AMD, or PowerPC CPUs can’t do anything with this bytecode. Here is where a runtime environment comes in handy. This environment reads the bytecode file statement by statement and executes it on the actual microprocessor.

 

The java interpreter causes the program to be executed, with the following result:

 

C:\Users\User\Documents>java NinetyNineBottlesOfBeer

99 bottles of beer on the wall, 99 bottles of beer. Take one down, pass it around,

98 bottles of beer on the wall, 98 bottles of beer. Take one down, pass it around,

97 bottles of beer on the wall, 97 bottles of beer. Take one down, pass it around,

 

As an argument, the runtime environment java gets the name of the class that contains a main(...) method and is therefore considered executable. The specification must not be provided with the ending .class since in this case we are not referencing the file name, but the class name instead, as required.

 

Executing Single-File Source Code Programs Directly: If the entire program is in only one file (called single-file source code programs), the runtime environment can execute the program without a translation because the bytecode can be stored in the memory. Note the file suffix .java:

 

C:\Users\User\Documents>java NinetyNineBottlesOfBeer.java

99 bottles of beer on the wall, 99 bottles of beer. Take one down, pass it around,

98 bottles of beer on the wall, 98 bottles of beer. Take one down, pass it around,

97 bottles of beer on the wall, 97 bottles of beer. Take one down, pass it around,

 

Common Compiler and Interpreter Issues

If we work on the command-line level (shell) without an IDE, various issues can occur. If the path to the compiler hasn’t been set correctly, the command-line interpreter throws an error message in the following form:

 

$ javac NinetyNineBottlesOfBeer.java 1

The command is either misspelled or could not be found.

Please check the spelling and the environment variable 'PATH'.

 

On Unix, the message is short as usual:

 

javac: Command not found

 

So, the solution in this case is to include javac in the search path, as described earlier. If the compiler run was successful, you can call the interpreter via the java program. If you make a mistake in the name of the class or add the suffix .class to the class name, the interpreter will complain. When trying to bring the non-existent class Q to life, for instance, the interpreter writes the following message to the error channel:

 

C:\Users\User\Documents>java Q

Error: Could not find or load main class Q

Caused by: java.lang.ClassNotFoundException: Q

 

If the name of the class file is correct, but the main method doesn’t have the signature public static void main(String[]), the Java interpreter can’t find the method at which to begin program execution. For example, if you make a mistake with the main(...) method in NinetyNineBottlesOfBeer, the following error message will appear:

 

C:\Users\User\Documents>java NinetyNineBottlesOfBeer

Error: Main method not found in class NinetyNineBottlesOfBeer, please define the ma in method as:

   public static void main(String[] args)

or a JavaFX application class must extend javafx.application.Application

 

Note: The Java compiler javac and the launcher for Java applications java have a -help switch that shows more information.

 

Editor’s note: This post has been adapted from a section of the book Java: The Comprehensive Guide by Christian Ullenboom.

Recommendation

Java
Java

This is the up-to-date, practical guide to Java you’ve been looking for! Whether you’re a beginner, you’re switching to Java from another language, or you’re just looking to brush up on your Java skills, this is the only book you need. You’ll get a thorough grounding in the basics of the Java language, including classes, objects, arrays, strings, and exceptions. You'll also learn about more advanced topics: threads, algorithms, XML, JUnit testing, and much more. This book belongs on every Java programmer's shelf!

Learn More
Rheinwerk Computing
by Rheinwerk Computing

Rheinwerk Computing is an imprint of Rheinwerk Publishing and publishes books by leading experts in the fields of programming, administration, security, analytics, and more.

Comments