155

Most websites on the internet say:

"use the javac command to compile a .java file. Then run it using the java command"

But today I tried to run a java program without javac and I got a strange result.

Here are the contents of a file called hello.java:

public class Myclass {
 public static void main(String[] args){
    System.out.println("hello world");
  }
}

Then I ran:

$ javac hello.java

Which gives me this error:

hello.java:1: error: class Myclass is public, should be declared in a file named Myclass.java
public class Myclass {
       ^
1 error

But when I run it without the javac command, it executed without any errors.

$ java hello.java
hello world

Does the java command also compile the program? If yes, why do we need the javac command?

The version of my java is:

openjdk version "12.0.2" 2019-07-16
OpenJDK Runtime Environment (build 12.0.2+10)
OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode)
7
  • 13
    Which version are you using? I think they introduced Java Console in Java 9, and that might be what you experienced. Commented Sep 24, 2019 at 18:44
  • 7
    You need to match the class name with its filename - that's the Java standard. Just change the file name to Myclass.java and then from the command line compile it like this javac Myclass.java and then run it like this java Myclass. Commented Sep 24, 2019 at 18:45
  • 6
    yes, javac still used to compile if you don't want to deploy source code, or you have more than a single file (documentation of java for source-file option: Only used to launch a single source-file program.) Commented Sep 24, 2019 at 18:48
  • @Matthieu the output of "java -version" is: openjdk version "12.0.2" 2019-07-16 OpenJDK Runtime Environment (build 12.0.2+10) OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode) Commented Sep 24, 2019 at 18:50
  • 1
    @Milad - What happens is this - javac compiles the Java source into JVM specific interpreted bytecode and the java command loads it inside the JVM's ClassLoader. Commented Sep 24, 2019 at 18:57

5 Answers 5

207

Prior to Java 11, to run your code you have to first compile it, then you can run it. Here's an example:

javac test.java
java test

Since Java 11, you can still do javac + java, or you can run java by itself to compile and auto-run your code. Note that no .class file will be generated. Here's an example:

java test.java

If you run java -help, you'll see the various allowed usages. Here's what it looks like on my machine. The last one is what you ran into: java [options] <sourcefile> [args] which will "execute a single source-file program".

$ java -help
Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a single source-file program)

UPDATE:

As pointed out by @BillK, OP also asked:

why do we need the javac command?

The reason we need javac is to create .class files so that code can be created, tested, distributed, run, shared, etc. like it is today. The motivation for JEP 330 was to make it easier for "early stages of learning Java, and when writing small utility programs" without changing any other existing uses.

Sign up to request clarification or add additional context in comments.

9 Comments

thanks @CarlosHeuberger for the additional details. I made a small edit in my answer to reflect that it was introduced in Java 11.
@Spikatrix that's Java 8 (They dropped the 1. in 1.8 in newer releases)
You didn't answer the question why we still need javac--I think java only operates on the single file you supply it and previously compiled files. I believe you must compile all the other files you wish to use from the file you call.
This answer does not address why this new method does not result in a file name vs. class name error as reported by javac.
|
57

If you are running Java 11, there is a new feature that allows single source file execution. The single source compiler is more promiscuous in terms of class name versus file name, so that is how you are able to run but not successfully compile.

If you are on a previous version of Java, then your current hello.java does not compile, because of compile errors, specifically around the class name. So there's absolutely no way that calling java hello.java compiled your code, because it does not compile.

It seems most entirely likely that you were running some previously compiled code when executing the java command.

7 Comments

thank you, java version is: openjdk version "12.0.2" 2019-07-16 OpenJDK Runtime Environment (build 12.0.2+10) OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode)
check Using Source-File Mode to Launch Single-File Source-Code Programs: "The compiler does not enforce the optional restriction defined at the end of JLS ??7.6, that a type in a named package should exist in a file whose name is composed from the type name followed by the .java extension."
The Java scripting API and Java Single-File Source-Code Program Launch (JEP 330) are two completely separate and totally unrelated things.
@DavidConrad, updated verbiage accordingly. Thanks.
Appreciate the input, @T.J.Crowder. But, I'm fairly sure I meant to write it as is. Also, second definition in your links: Promiscuous means including a wide range of different things.
|
9

To answer why this error is given, the class name for the file must match the file's basename.

You have two options to have this code work for the traditional javac; java sequence:

  1. Rename the class to public class Hello or

  2. Rename hello.java to myclass.java.

The java interpreter for Java 11 does not impose this requirement. The class that contains main can have any name, as long as it is the first class in the file. This was mainly intended to ease the learning process for beginners, and to allow "java scripting" with the shebang (ref.).

Comments

7

Yes, but not in the way you probably mean.

When you use the javac command to compile a .java file to a .class file the output is something called bytecode. Bytecode is a the machine code (native instructions) for a theoretical CPU based on the Java Virtual Machine specification.

This virtual CPU specification is sort of an average of types of CPUs that were common at the time the specification was written. Because of this it is close to lots of different types of CPU making it easier to run the same Java .class files on multiple CPU types.

When Java was first launched the java command would read the .class file and interpret the bytecode instructions one at a time and then map them to the equivalent native instruction for what ever CPU it was actually running on. This worked but wasn't particularly fast. To improve this Just in Time (JIT) compilation was added to the Java Runtime.

With JIT the java command takes the bytecode and compiles it again to the native instructions for the CPU it is running on. Modern Java runtimes tend to start out interpreting the bytecode while JIT compiling in the background and switch to the compiled native instructions when it's ready and will also profile the running application and then recompile the bytecode again with different optimisation to get the best possible performance.

EDIT (to appease the down voters):

So in your specific case (as you are running a JRE newer than v11) the code is compiled (at least) twice

  1. As a single .java file to bytecode
  2. Via the JIT compiler as it interprets the bytecode (though for helloWorld it might not actually get time to run any of the compiled native code)

4 Comments

This doesn't answer the question.
@DavidConrad But it does! The answer to "Does the 'java' command compile Java programs?" is a resounding "yes" for the reasons hardlib gives here: it will compile byte code to native instructions just-in-time (for non-trivial programs, with standard settings).
Is compilation now mandatory? Historically Java byte code could be interpreted; JIT compilation was optional.
The JIT is on by default these days (for a very long time), as show by the mixed-mode in the version output
-1

enter image description hereThe command to run the java file is using java filename. ie: simply create a file in notepad and enter the java code inside the file, the name of the file should same as the Main class in our code then save the file as Myclass.java(example), then open the command prompt and run javac Myclass.java it will create a class file in the location where file is created then use java Myclass to run the program, we can't simply run using java Myclass we have to convert it to class file using javac command so that virtual machine will read the code.

code:

Main.java

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

Thanks.

5 Comments

and using java command we can compile the program Don't you mean: and using java command we can RUN the program ?
So edit your answer and correct it.
Yes we can run, the command to run the java file is using java filename. ie: simply create a file in notepad and enter the java code inside the file, the name of the file should same as the Main class in our code then save the file as Myclass.java(example), then open the command prompt and run javac Myclass.java it will create a class file in the location where file is created then use java Myclass to run the program, we can't simply run using java Myclass we have to convert it to class file using javac command so that virtual machine will read the code. Thanks,
Just click on the link in my other comment and you can edit your answer. Your comment should be part of your answer.
Please punctuate, capitalize, and paragraph this illegible mess.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.