Let's assume I would like to execute a Java application:
java -cp j1:j2...:j9999 Main arg1 arg2
In this case, the java executable gets a plethora of arguments which, on certain OSes, can cause problems due to the length limitation of the command line string (see Maximum Length of Command Line String).
As a remedy, javac offers the #argfile (see here) which allows specifying the arguments within a file. The above example would look like this, if java supported it as well:
java #FileContainingArguments.txt
and the content of FileContainingArguments.txt is:
-cp j1:j2...:j9999
Main
arg1
arg2
So the question is, why java doesn't support it, while javac and javadoc do?
I don't know why it is not supported yet, but it seems Open JDK 9 will support it, once it is released:
https://bugs.openjdk.java.net/browse/JDK-8027634. I am not sure about Oracle.
Related
Why do we need to prefix JVM arguments with -D e.g. when running a jar from the command line? E.g.
java -jar -DmyProp="Hello World" myProgram.jar
is used to run myProgram.jar with the system parameter myProp. So why the leading -D? Why couldn't the architects of Java let us simply do:
java -jar -myProp="Hello World" myProgram.jar
I'm hoping for an answer beyond just "Because that's the way it is".
Bonus Question: Why the letter -D as opposed to any other letter, does it stand for anything?
Note: This question asks why there was a need to use "D", or any other letter for that matter, in the first place. It is less concerned with the choice of specific letter "D" over any other letter, though that is asked as a bonus question.
The bonus question has an answer here: In java -D what does the D stand for?.
Why couldn't the architects of Java let us simply do:
java -jar -myProp="Hello World" myProgram.jar
It could work today but suppose that in next Java versions a -myProp argument is introduced as a JVM option.
How to distinguish your -myProp from the -myProp JVM option ? No way.
So it exists an obvious reason to use -D to define system properties.
As other example, instead of -myProp suppose you program relies on a -client system property.
It will not run :
java -jar -client="davidxxx" myProgram.jar
You would have a JVM error such as :
Unrecognized option: -client=davidxxx
as -client is a JVM standard option that expects no value.
But if you use -D-client, it is now fine as here -Dclient is defined as a system property that is distinct from the -client standard JVM option :
java -jar -D-client="davidxxx" myProgram.jar
Or by using both :
java -jar -client -D-client="davidxxx" myProgram.jar
To go further, not all JVM arguments start with -D. but most of them have a prefix (-D, -X, -XX) that allows in a someway to define namespaces.
You have distinct categories of JVM arguments :
1. Standard Options (-D but not only).
These are the most commonly used options that are supported by all implementations of the JVM.
You use -D to specify System properties but most of them don't have any prefix :-verbose, -showversion, and so for...
2. Non-Standard Options (prefixed with -X)
These options are general purpose options that are specific to the Java HotSpot Virtual Machine.
For example : -Xmssize, -Xmxsize
3. Advanced Runtime Options (prefixed with -XX)
These options control the runtime behavior of the Java HotSpot VM.
4. Advanced JIT Compiler Options (prefixed with -XX)
These options control the dynamic just-in-time (JIT) compilation performed by the Java HotSpot VM.
5. Advanced Serviceability Options (prefixed with -XX)
These options provide the ability to gather system information and perform extensive debugging.
6. Advanced Garbage Collection Options (prefixed with -XX)
These options control how garbage collection (GC) is performed by the Java HotSpot VM.
"Define". The meaning is similar to a preprocessor definition in C. The -D signifies that the definition is in the context of the application, and not in the Java interpreter context like any other option before the executable name.
The usage of the letter "D" isn't specifically explained in the documentation, but the only use is to "define" a key in the system properties map - except for this reference:
The System class maintains a Properties object that defines the configuration of the current working environment. For more about these properties, see System Properties. The remainder of this section explains how to use properties to manage application configuration.
If you do not specify anything like -myProp="XYZ" it means it is passed as an argument to main method of the program.
-D means you can use this value using System.getProperty
-X is used for extension arguments like -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
Yes, they could have interchanged.. the characters; but these characters are used to specify what type of parameter is passed and who is the consumer.
Without the -D the properties would conflict with normal JVM options. For example how would you set the property jar?
The -D was probably chosen (I can only speculate about that) because it is also used in the C preprocessor to define symbols and was therefore familiar to most people.
I just picked up my Ubuntu machine after a long time for some java related work and found that I have java already installed but not javac.
I made a Test.java file with a main method and a simple print statement. I wrote this in my terminal:
java Test.java
I expected that without javac this shouldn't compile and run but it printed the output on my console. I then installed a JDK to enable the javac and ran this:
javac Test.java
This created a Test.class file. Still to run the Test class I need to type java Test.java and on typing java Test it throws java.lang.NoClassDefFoundError.
Can someone please explain to me what's happening in the background of these commands?
Edit:
Here are the contents of my Test.java:
package Learning;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Hello World!");
}
}
What you experience here is a new feature, added for Java 11:
In Java SE 11, you get the option to launch a single source code file directly, without intermediate compilation. Just for your convenience, so that newbies like you don't have to run javac + java (of course, leaving them confused why that is).
Quoted from here. For more details, see the corresponding JEP 330.
So: if you have a single self-contained .java file ... then the java binary recognizes that, compiles it, and directly runs it (when using Java 11 or newer).
But keep in mind: it is just that, a way to quickly run a single class. It isn't meant to replace the "real" way of doing things.
In general, you still use javac first, and then java. Or, more real world: you use a built system where you describe what to build, and then the build system invokes javac for you behind the covers.
GhostCat's answer is good, but here are a few additions taken from a longer post about this same behavior.
Can someone please explain to me what's happening in the background of these commands?
What you ran into – where you can use "java" (not "javac") to
compile and run a program in one command – JEP 330: Launch Single-File Source-Code Programs –
was designed to make it easier for "early stages of learning Java, and when writing small utility programs".
It's definitely
not meant to replace anything – use it if convenient, but nothing changes with the normal steps of "compile to .class file" and "run JVM using .class files or JARs".
There's some good info in the JEP 330 link, but also in the java command itself, namely that one option (among four total) is to provide a single filename (which is what you did)
To launch a single source-file program:
java [options] source-file [args ...]
Further, there's a nice summary in Using Source-File Mode to Launch Single-File Source-Code Programs:
In source-file mode, the effect is as though the source file is compiled into memory, and the first class found in the source file is executed. Any arguments placed after the name of the source file in the original command line are passed to the compiled class when it is executed.
I have a running java program which converts a json file into another file format. Everything works great.
For the implementation I decided to use the MVC pattern.
Now I want to implement the whole conversion routine so that I can use a command prompt but I never worked with that and don't know how to achieve this at all.
My thoughts were:
Open cmd and navigate to the main.java-file.
Print out the whole possibilities (the user should be able to enter the dir of the source file and the target dir, the user should be able to choose the target format).
If everything has been entered by the user, the conversion routine should be started by pushing ENTER.
Help would be really nice. For the moment I just know how to compile (javac helloWorld.java) and print "Hello World!" by exeuting a program with java helloWorld...
The apache commons cli project provides utilities for parsing command line arguments and providing help menu. This makes it pretty simple to handle the args provided to your main method.
You will also need to provide scripts to assemble your class path. You can look at the maven app assembler plugin for ways of doing this.
The interaction between a shell/command prompt and the started Java program is very similar to the way it works in C programs*. The main() method receives arguments as strings from the command line (or from any other parent process which executes the java runtime).
In Java you get an array of strings. You need to decide yourself which string has what meaning.
public static void main(String[] arg) { // traditional or String ... args
System.out.println("You have " + arg.length + " arguments);
if (arg.length >= 1) System.out.println("First: " + arg[0]);
}
When starting a Java runtime with arguments, it is important to note, that arguments start after the class name (or the JAR name):
java -cp . package.Main arg0 arg1 ...
java -jar package.jar arg0 arg1 ...
The Java runtime also has an mechanism to specify system properties on the command line. This is done with the -D option.
java -Dverbose=yes -jar package.jar arg0 arg1 ...
java -jar package.jar -Dverbose=yes arg1 ... //not a system property but arg[0]
It is important, that this option is specified before the class/jar-name, otherwise it will not be processed by the runtime, but you will see another argument.
String verbose = System.getProperty("verbose", "false");
The reason why system properties are useful: you can use them for optional control, so you do not have to worry about recognizing arguments (there are a number of libraries out there which can do that but for small tools I think it is overkill).
BTW: there are some interactions between shells/prompts and started programs when using wildcards (* and ?) and whitespace/quoting - those are OS specific.
* in C the first argument args[0] is the program name, in java arg[0] is the first argument after the class name.
I am running java code with ant javac. I ran ant script in eclipse and command line. but the Java class files are differ in size. Can you please explain why there is a size differece when using javac ant script in eclipse and commandline. and how can I resolve it.
Java Compiler may or may not include the following into bytecode I know of:
Java annotations
Javadoc specific info
There should be a difference between the actual javac parameters when it's called. Check Ant's config and javac's default parameter values. The target Java platform version may differ too which causes .class file size differences.
If there are multiple JDK-s utilized, of course that means different class file sizes too.
javac by default generates only line numbers in debugging info (see javac -g). In Eclipse all vars, lines and source in compiler classfile generation options are enabled.
There's nothing to "resolve"; Eclipse uses its own built-in incremental compiler, and it's entirely common for compilers to produce slightly different output from the same programs.
I have a program where I have to take paths from the command line as input, likely with wildcards such as ?, * and **. Java persists in expanding these paths on it's own, usually screwing up.
For instance:
java -jar myapp.jar C:/Hello/World/*
Gives me a String[] args that looks like this:
["C:\Hello\World\foo", "C:\Hello\World\bar"]
Not only is this extremely troublesome, it also messes up the ** wildcard:
java -jar myapp.jar C:/Hello/World/**
Gives the same thing as before, when ** should be a recursive search. I have an algorithm for doing this efficiently, which I originally developed on python, but it's pointless if I can't use it. Is there a way to prevent this from happening?
EDIT = I tried using different shells (PowerShell, cmd, eclipse), using different formats (no quotes, quotes, double quotes) and none of them worked.
Java is not doing that, it's your shell.
Quote the arguments:
java -jar myapp.jar 'C:/Hello/World/**'
Or
java -jar myapp.jar "C:/Hello/World/**"
This could be completely wrong, but try this:
java -jar myapp.jar C:/Hello/World/\*