Does the 'java' command compile Java programs? - java

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)

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.

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.

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:
Rename the class to public class Hello or
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.).

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
As a single .java file to bytecode
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)

Related

Difference between using javac<file> and java<file>

From some experienced java coders I want to ask what is difference between using
javac <filename>
java <file_name_without_extention>
And
java <filename>
They're equivalent if your source code is only a single file. The former (with the two commands) is the general way to compile and run Java source code, and it's still the correct way to compile larger projects. The latter is a new feature added in JDK 11 to make it easier to run individual files and very small programs.
From the proposal that suggested the feature
In source-file mode, the effect is as if the source file is compiled
into memory, and the first class found in the source file is executed.
For example, if a file called HelloWorld.java contains a class called
hello.World, then the command
java HelloWorld.java
is informally equivalent to
javac -d <memory> HelloWorld.java
java -cp <memory> hello.World
javac <Filename> - a java command that compiles java source files into bytecodes.
It needs an extension because you are compiling the source file.
java -cp <classpath> <Classname> - a java command that executes the compiled bytecodes.
It does not need an extension because you are merely telling it to search for the Class and its main() signature from the classpath to execute.

Java 11: Executing Source File via Shebang is not working

I wanted to check out some new features of java 11 which was released two days ago.
JEP 330 states that I could launch a Java-Source-Code-Program without compiling.
It should also support the usage of Shebang-Files.
Hence I have written this small Hello-World Program Test.java:
#!/opt/java/jdk-11/bin/java --source 11
public class Test
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
I downloaded JDK 11 and extracted it to /opt/java.
Hence the Shebang itself is working.
I.e. executing /opt/java/jdk-11/bin/java --version gives me
openjdk 11 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
After making Test.java executable (using chmod +x Test.java) the execution is failing.
I.e. ./Test.java gives me:
./Test.java:1: error: illegal character: '#'
#!/opt/java/jdk-11/bin/java --source 11
^
./Test.java:1: error: class, interface, or enum expected
#!/opt/java/jdk-11/bin/java --source 11
^
2 errors
error: compilation failed
As soon as I remove the Shebang-Line from Test.java and start it with /opt/java/jdk-11/bin/java --source 11 Test.java
everything is working like a charm and I get the expected output: Hello World!
My machine is running Ubuntu 17.04.
I have linked javac to the one from JDK 11 (i.e. executing javac -version gives javac 11).
The file name must not end with .java in order for the java executable to ignore the shebang line. You can use a different extension, or just have no extension at all (which is what they do in the JEP example and is what I would recommend).
From JEP 330 (emphasis added):
When the launcher reads the source file, if the file is not a Java source file (i.e. it is not a file whose name ends with .java) and if the first line begins with #!, then the contents of that line up to but not including the first newline are ignored when determining the source code to be passed to the compiler. The content of the file that appears after the first line must consist of a valid CompilationUnit as defined by ยง7.3 in the edition of the Java Language Specification that is appropriate to the version of the platform given in the --source option, if present, or the version of the platform being used to run the program if the --source option is not present.
It doesn't need to end with ".sh" specifically; also, that's potentially misleading because the file is not actually a shell script.
A bit of trial and error gave me the correct solution.
It was the file extension .java which causes those problems.
I.e. if I rename the file to Test.sh everything is working.
Here is a complete Hello-World-Shebang-Example:
Create a File Test.sh with content like
#!/opt/java/jdk-11/bin/java --source 11
public class Test
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
Make it executable (i.e. chmod +x Test.sh).
Last but not least execute it using ./Test.sh
According to the JEP you've linked to (see the shebang files section), the shebang file is to be used to launch the java process, not to be used as a parameter for java:
A shebang file to invoke the Java launcher using source-file mode must begin with something like:
#!/path/to/java --source version
For example, we could take the source code for a "Hello World" program, and put it in a file called hello, after an initial line of #!/path/to/java --source 10, and then mark the file as executable. Then, if the file is in the current directory, we could execute it with:
$ ./hello
In other words, what you want to do is rather make Test.java executable. You'd also have to rename it since it won't work as shebang and strip first line when it's named *.java.
$ move Test.java test
$ chmod +x test
$ ./test
This will launch shebang processor which will strip first line and pass the rest of the script to /path/to/java and Java will compile the script and run the main method.

Process behind how system will take the particular path from environmental variables (At the time of using java commands)

At the time of compiling or using the java commands (ex: javac, java), how the system will take the particular Java Path set in an Environmental variable?
I know it will take and I know about environmental variables. I Just want to know how the system will take. Can any one explain the process behind it??
CLASSPATH environment variable may be used to define a classpath instruction for java and javac (and other JDK tools). You could do the following on Unix-like systems (for example, Linux):
export CLASSPATH=/home/user/path/to/dir1:/home/user/path/to/dir2:/opt/other-dir
Then, when you execute java or javac, having that environment variable would have the effect of adding a -classpath key, for example
javac Test.java
will work in the same way as the following command would work without any environment variable defined:
javac -classpath /home/user/path/to/dir1:/home/user/path/to/dir2:/opt/other-dir Test.java
More information: https://docs.oracle.com/javase/tutorial/essential/environment/paths.html
How java reads this property from OS
Source is available here: http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/bin/java.c
cpath = getenv("CLASSPATH");
They use getenv() function from C library: https://www.tutorialspoint.com/c_standard_library/c_function_getenv.htm

Javac vs Java within -classpath option

What is the difference in calling the -classpath option from javac and from java
for example:
javac -classpath MyJar.jar GetJar.java
java -classpath MyJar.jar:. GetJar
it works as well as:
javac -classpath MyJar.jar GetJar.java
java GetJar
So basically where the first -classpath related to javac needs to be there, on the other hand in the java command line it might be optional. Why? Do you know in which circumstance it would be mandatory. And more in general what is the effect of -classpath called by javac and what is the effect of -classpath called by java.
Thanks in advance.
One is the classpath used for compiling. The other is the classpath used for running. And they do not have to be the same thing. The set of classes needed for the compilation processes are all those referred to by every class being compiled. Whereas your runtime JAR could be invoking a standalone class with an empty main method and no dependencies.
Just remember that at runtime class dependencies are resolved dynamically, aka a class is only loaded when it is needed (this is a generalization, boot and system classes are always loaded).
This document contains answers for your questions
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javac.html
using -classpath every time is a very time consuming work. Instead, use environment variables (if you are dealing with a package such as Java Mail)
classpath is used for compiling. Javac is the Java Compiler, where it converts your code into byte code.
When it comes to java it is used to run your Java source file/jar.

Can java run a compiled scala code?

Can command java run a compiled scala code? If so, why do we have an exclusive command scala?
You can run byte code generated by Scala if you include all necessary runtime libs for Scala (scala-library.jar, scala-swing.jar ...) in the classpath. The scala command does this automatically, and supports Scala specific command line arguments.
Yes, it can. Scala is compiled down to Java bytecode. But remember that it depends on the Scala runtime classes, so you need to still have Scala's jar files on the classpath.
If so, why do we have an exclusive command scala?
Convenience wrapper.
Scala is designed to integrate easily
with applications that run on modern
virtual machines, primarily the Java
virtual machine (JVM). The main Scala
compiler, scalac, generates Java class
files that can be run on the JVM.
-> http://www.artima.com/scalazine/articles/steps.html
As long as you have installed the scala runtime you should be fine: compile classes with scalac and run them with java.
Just want to add my own answer as additional value for the future readers:
scala, if run without parameter, will run an interactive shell
scala, if run with a text file name as parameter, will regard the file as a scala script
those two can't be done using java
If you look closely, the scala command is simply a bash helper-script which summarize to the below command:
$cat /usr/local/Cellar/scala#2.11/2.11.12_1/libexec/bin/scala
execCommand \
"${JAVACMD:=java}" \
$JAVA_OPTS \
"${java_args[#]}" \
"${classpath_args[#]}" \
-Dscala.home="$SCALA_HOME" \
$OVERRIDE_USEJAVACP \
"$EMACS_OPT" \
$WINDOWS_OPT \
scala.tools.nsc.MainGenericRunner "$#"
There are 2 things required to run a .class file compiled using scalac ( the scala compiler) using the java command.
We need to include the scala-library.jar and the location of the .class file in the classpath. To find the location of scala-library.jar, please execute the
below:
which scala /usr/local/opt/scala#2.11/bin/scala
In my case the scala-*.jar files are in :
/usr/local/Cellar/scala#2.11/2.11.12_1/idea/lib on Mac
The location of the Main2.class file which is in /training/example1/scala.
So, to execute the program we could use the below command:
java -cp /usr/local/Cellar/scala#2.11/2.11.12_1/idea/lib/scala-library.jar:/training/example1/scala/ Main2
EDIT-1: If you are using windows, please use semicolon(;) as the separator in java classpath command.

Categories