JAVAC(1)
okay so bestie, this is javac(1) straight out of the JDK Commands manual, and it's literally the whole compiler vibe. let's get into it ๐ซถ
๐ธ NAME ๐ธ
javac โ reads your Java declarations and compiles them into class files. that's the whole job, and she does it flawlessly. โจ
โจ SYNOPSIS โจ
javac [options] [sourcefiles-or-classnames]
optionsโ command-line options, aka the little knobs you turn.sourcefiles-or-classnamesโ the source files you wanna compile (likeShape.java), or the names of classes you already compiled before that are being processed for annotations (likegeometry.MyShape). both count, no cap ๐
๐ DESCRIPTION ๐
so the javac command reads source files containing module, package, and type declarations written in the Java programming language, and compiles them into class files that run on the Java Virtual Machine. iconic behavior, honestly.
javac can also process annotations in Java source files and classes. multipurpose queen ๐
source files must have a file name extension of .java. class files have a file name extension of .class. both source and class files normally have file names that identify their contents โ like, a class called Shape would be declared in a source file called Shape.java, and compiled into a class file called Shape.class. it's giving matching set ๐
there are two ways to specify source files to javac:
- for a small number of source files, you can just list their file names on the command line.
- for a large number of source files, you can use the
@filenameoption on the command line to specify an argument file that lists their file names. See Standard Options for a description of the option, and Command-Line Argument Files for a description ofjavacargument files. ๐๏ธ
the order of source files specified on the command line or in an argument file is not important. javac will compile the files together, as a group, and will automatically resolve any dependencies between the declarations in the various source files. she figures it out, fr fr.
javac expects that source files are arranged in one or more directory hierarchies on the file system, described in Arrangement of Source Code.
to compile a source file, javac needs to find the declaration of every class or interface that is used, extended, or implemented by the code in the source file. this lets javac check that the code has the right to access those classes and interfaces. rather than specifying the source files of those classes and interfaces explicitly, you can use command-line options to tell javac where to search for their source files. if you've compiled those source files previously, you can use options to tell javac where to search for the corresponding class files. the options โ which all have names ending in "path" โ are described in Standard Options, and further described in Configuring a Compilation and Searching for Module, Package and Type Declarations. lowkey a whole lore drop ๐ฆ
by default, javac compiles each source file to a class file in the same directory as the source file. but it is recommended to specify a separate destination directory with the -d option. do it. trust. ๐
command-line options and environment variables also control how javac performs various tasks:
- compiling code to run on earlier releases of the JDK.
- compiling code to run under a debugger.
- checking for stylistic issues in Java source code.
- checking for problems in javadoc comments (
/** ... */). - processing annotations in source files and class files.
- upgrading and patching modules in the compile-time environment.
javac supports Compiling for Earlier Releases Of The Platform, and can also be invoked from Java code using one of a number of APIs.
๐ OPTIONS ๐
javac provides standard options, plus extra options that are either non-standard or are for advanced use. (the advanced ones are giving โจmain character energyโจ)
some options take one or more arguments. if an argument contains spaces or other whitespace characters, the value should be quoted according to the conventions of the environment being used to invoke javac. and here's the syntax tea โ:
- if the option begins with a single dash (
-), the argument should either directly follow the option name, or should be separated with a colon (:) or whitespace, depending on the option. - if the option begins with a double dash (
--), the argument may be separated either by whitespace or by an equals (=) character with no additional whitespace.
for example:
-Aname="J. Duke"
-proc:only
-d myDirectory
--module-version 3
--module-version=3
in the following lists of options, an argument of path represents a search path โ composed of a list of file system locations separated by the platform path separator character (semicolon ; on Windows, or colon : on other systems). depending on the option, the file system locations may be directories, JAR files or JMOD files. ๐ง
๐ Standard Options ๐
@filenameโ reads options and file names from a file. to shorten or simplify thejavaccommand, you can specify one or more files that contain arguments to thejavaccommand (except-Joptions). this lets you createjavaccommands of any length on any operating system. See Command-Line Argument Files. ๐-Akey[=value]โ specifies options to pass to annotation processors. these options are not interpreted byjavacdirectly, but are made available for use by individual processors. thekeyvalue should be one or more identifiers separated by a dot (.). ๐--add-modules module,moduleโ specifies root modules to resolve in addition to the initial modules, or all modules on the module path ifmoduleisALL-MODULE-PATH. ๐งฉ--boot-class-path pathor-bootclasspath pathโ overrides the location of the bootstrap class files.
note: this can only be used when compiling for releases prior to JDK 9. as applicable, see the descriptions in--release,-source, or-targetfor details. for JDK 9 or later, see--system. โ ๏ธ
--class-path path,-classpath path, or-cp pathโ specifies where to find user class files and annotation processors. this class path overrides the user class path in theCLASSPATHenvironment variable.- if
--class-path,-classpath, or-cpare not specified, then the user class path is the value of theCLASSPATHenvironment variable, if that is set, or else the current directory. - if not compiling code for modules, and if the
--source-pathor-sourcepathoption is not specified, then the user class path is also searched for source files. - if the
-processorpathoption is not specified, then the class path is also searched for annotation processors.
- if
-d directoryโ sets the destination directory (or class output directory) for class files. if a class is part of a package, thenjavacputs the class file in a subdirectory that reflects the module name (if appropriate) and package name. the directory, and any necessary subdirectories, will be created if they do not already exist. ๐๏ธ
if the -d option is not specified, then javac puts each class file in the same directory as the source file from which it was generated.
except when compiling code for multiple modules, the contents of the class output directory will be organized in a package hierarchy. when compiling code for multiple modules, the contents of the output directory will be organized in a module hierarchy, with the contents of each module in a separate subdirectory, each organized as a package hierarchy.
note: when compiling code for one or more modules, the class output directory will automatically be checked when searching for previously compiled classes. when not compiling for modules, for backwards compatibility, the directory is not automatically checked for previously compiled classes โ and so it is recommended to specify the class output directory as one of the locations on the user class path, using the --class-path option or one of its alternate forms. ๐ญ (this one bites people, bestie)
-deprecationโ shows a description of each use or override of a deprecated member or class. without the-deprecationoption,javacshows a summary of the source files that use or override deprecated members or classes. the-deprecationoption is shorthand for-Xlint:deprecation. ๐--enable-previewโ enables preview language features. used in conjunction with either-sourceor--release. ๐-encoding encodingโ specifies character encoding used by source files, such asEUC-JPandUTF-8. if the-encodingoption is not specified, then the platform default converter is used. ๐-endorseddirs directoriesโ overrides the location of the endorsed standards path.
note: this can only be used when compiling for releases prior to JDK 9. as applicable, see the descriptions in--release,-source, or-targetfor details. โ ๏ธ
-extdirs directoriesโ overrides the location of the installed extensions.directoriesis a list of directories, separated by the platform path separator (;on Windows, and:otherwise). each JAR file in the specified directories is searched for class files. all JAR files found become part of the class path.
if you are compiling for a release of the platform that supports the Extension Mechanism, then this option specifies the directories that contain the extension classes. See [Compiling for Other Releases of the Platform].
note: this can only be used when compiling for releases prior to JDK 9. as applicable, see the descriptions in--release,-source, or-targetfor details. โ ๏ธ
-gโ generates all debugging information, including local variables. by default, only line number and source file information is generated. ๐-g:[lines, vars, source]โ generates only the kinds of debugging information specified by the comma-separated list of keywords. valid keywords are:linesโ line number debugging information.varsโ local variable debugging information.sourceโ source file debugging information.
-g:noneโ does not generate debugging information. ๐-h directoryโ specifies where to place generated native header files. ๐๏ธ
and that's just the first chunk of the flags, bestie โ she's got so much more where that came from ๐
Okay so about that native header option, bestie: when you specify it, a native header file gets generated for each class that contains native methods or that has one or more constants annotated with the java.lang.annotation.Native annotation. If the class is part of a package, then the compiler puts the native header file in a subdirectory that reflects the module name (if appropriate) and package name. The directory, and any necessary subdirectories, will be created if they do not already exist. โจ
--help,-helpor-?โ prints a synopsis of the standard options. ๐ซถ--help-extraor-Xโ prints a synopsis of the set of extra options. ๐--help-lintโ prints the supported keys for the-Xlintoption. ๐-implicit:[none, class]โ specifies whether or not to generate class files for implicitly referenced files:-implicit:class--- automatically generates class files.-implicit:none--- suppresses class file generation.
If this option is not specified, then the default automatically generates class files. In this case, the compiler issues a warning if any class files are generated when also doing annotation processing. The warning is not issued when the -implicit option is explicitly set. See Searching for Module, Package and Type Declarations. ๐
-Joptionโ passes option to the runtime system, where option is one of the Java options described on thejavacommand. For example,-J-Xms48msets the startup memory to48 MB. โญ
Note: TheCLASSPATHenvironment variable,-classpathoption,-bootclasspathoption, and-extdirsoption do not specify the classes used to runjavac. Trying to customize the compiler implementation with these options and variables is risky and often does not accomplish what you want. If you must customize the compiler implementation, then use the-Joption to pass options through to the underlying Java launcher. ๐
--limit-modules module,module*โ limits the universe of observable modules. ๐ฆ--module module-name (,module-name)*or-m module-name (,module-name)*โ compiles those source files in the named modules that are newer than the corresponding files in the output directory. ๐ฅ--module-path pathor-p pathโ specifies where to find application modules. ๐ธ--module-source-path module-source-pathโ specifies where to find source files when compiling code in multiple modules. See[Compilation Modes]and The Module Source Path Option. ๐ง--module-version versionโ specifies the version of modules that are being compiled. ๐-nowarnโ disables warning messages. This option operates the same as the-Xlint:noneoption. ๐-parametersโ generates metadata for reflection on method parameters. Stores formal parameter names of constructors and methods in the generated class file so that the methodjava.lang.reflect.Executable.getParametersfrom the Reflection API can retrieve them. โจ-proc:[none, only, full]โ controls whether annotation processing and compilation are done.-proc:nonemeans that compilation takes place without annotation processing.-proc:onlymeans that only annotation processing is done, without any subsequent compilation. If this option is not used, or-proc:fullis specified, annotation processing and compilation are done. ๐-processor class1[,class2,class3...]โ names of the annotation processors to run. This bypasses the default discovery process. ๐--processor-module-path pathโ specifies the module path used for finding annotation processors. ๐--processor-path pathor-processorpath pathโ specifies where to find annotation processors. If this option is not used, then the class path is searched for processors. ๐-profile profileโ checks that the API used is available in the specified profile. This option is deprecated and may be removed in a future release. ๐
Note: This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in--release,-source, or-targetfor details. ๐ญ
--release releaseโ compiles source code according to the rules of the Java programming language for the specified Java SE release, generating class files which target that release. Source code is compiled against the combined Java SE and JDK API for the specified release. ๐
The supported values of release are the current Java SE release and a limited number of previous releases, detailed in the command-line help. ๐
For the current release, the Java SE API consists of the java.*, javax.*, and org.* packages that are exported by the Java SE modules in the release; the JDK API consists of the com.* and jdk.* packages that are exported by the JDK modules in the release, plus the javax.* packages that are exported by standard, but non-Java SE, modules in the release. ๐
For previous releases, the Java SE API and the JDK API are as defined in that release. ๐ฆ
Note: When using--release, you cannot also use the--source/-sourceor--target/-targetoptions. ๐
Note: When using--releaseto specify a release that supports the Java Platform Module System, the--add-exportsoption cannot be used to enlarge the set of packages exported by the Java SE, JDK, and standard modules in the specified release. โผ๏ธ
-s directoryโ specifies the directory used to place the generated source files. If a class is part of a package, then the compiler puts the source file in a subdirectory that reflects the module name (if appropriate) and package name. The directory, and any necessary subdirectories, will be created if they do not already exist. ๐
Except when compiling code for multiple modules, the contents of the source output directory will be organized in a package hierarchy. When compiling code for multiple modules, the contents of the source output directory will be organized in a module hierarchy, with the contents of each module in a separate subdirectory, each organized as a package hierarchy. ๐ธ
--source releaseor-source releaseโ compiles source code according to the rules of the Java programming language for the specified Java SE release. The supported values ofreleaseare the current Java SE release and a limited number of previous releases, detailed in the command-line help. ๐ซถ
If the option is not specified, the default is to compile source code according to the rules of the Java programming language for the current Java SE release. โญ
--source-path pathor-sourcepath pathโ specifies where to find source files. Except when compiling multiple modules together, this is the source code path used to search for class or interface definitions. ๐ง
Note: Classes found through the class path might be recompiled when their source files are also found. See Searching for Module, Package and Type Declarations. ๐
--system jdk | noneโ overrides the location of system modules. ๐--target releaseor-target releaseโ generates class files suitable for the specified Java SE release. The supported values ofreleaseare the current Java SE release and a limited number of previous releases, detailed in the command-line help. ๐ฅ
Note: The target release must be equal to or higher than the source release. (See --source.) ๐
--upgrade-module-path pathโ overrides the location of upgradeable modules. ๐-verboseโ outputs messages about what the compiler is doing. Messages include information about each class loaded and each source file compiled. ๐--versionor-versionโ prints version information. โจ-Werrorโ terminates compilation when warnings occur. ๐
โจ Extra Options โจ
--add-exports module/package=other-module(,other-module)*โ specifies a package to be considered as exported from its defining module to additional modules or to all unnamed modules when the value ofother-moduleisALL-UNNAMED. ๐--add-reads module=other-module(,other-module)*โ specifies additional modules to be considered as required by a given module. ๐ฆ--default-module-for-created-files module-nameโ specifies the fallback target module for files created by annotation processors, if none is specified or inferred. ๐-Djava.endorsed.dirs=dirsโ overrides the location of the endorsed standards path. ๐ธ
Note: This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in--release,-source, or-targetfor details. ๐ญ
-Djava.ext.dirs=dirsโ overrides the location of installed extensions. ๐
Note: This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in--release,-source, or-targetfor details. ๐ญ
--patch-module module=pathโ overrides or augments a module with classes and resources in JAR files or directories. ๐ง-Xbootclasspath:pathโ overrides the location of the bootstrap class files. ๐ฅ
Note: This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in--release,-source, or-targetfor details. ๐ญ
-Xbootclasspath/a:pathโ adds a suffix to the bootstrap class path. โญ
Note: This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in--release,-source, or-targetfor details. ๐ญ
-Xbootclasspath/p:pathโ adds a prefix to the bootstrap class path. ๐
Note: This can only be used when compiling for releases prior to JDK 9. As applicable, see the descriptions in--release,-source, or-targetfor details. ๐ญ
-Xdiags:[compact, verbose]โ selects a diagnostic mode. ๐ซถ-Xdoclintโ enables recommended checks for problems in documentation comments. ๐-Xdoclint:(all|none|[-]group)[/access]โ enables or disables specific groups of checks in documentation comments. ๐
group can have one of the following values: accessibility, html, missing, reference, syntax. ๐
Okay so the variable access (yes, the access part) sets the minimum visibility level of classes and members that the -Xdoclint option checks. It can be one of these values, listed from most visible to least visible: public, protected, package, private.
The default access level is private. Lowkey important, bestie ๐
When prefixed by doclint:, the group names and all can be used with @SuppressWarnings to suppress warnings about documentation comments in parts of the code being compiled.
For more information about these groups of checks, see the DocLint section of the javadoc command documentation. The -Xdoclint option is disabled by default in the javac command.
For example, the following option checks classes and members (with all groups of checks) that have the access level of protected and higher (which includes protected and public):
-Xdoclint:all/protected
The following option enables all groups of checks for all access levels, except it will not check for HTML errors for classes and members that have the access level of package and higher (which includes package, protected, and public):
-Xdoclint:all,-html/package
-Xdoclint/package:[-]packages(,[-]package)*โ Enables or disables checks in specific packages. Each package is either the qualified name of a package or a package name prefix followed by.*, which expands to all sub-packages of the given package. Each package can be prefixed with a hyphen (-) to disable checks for a specified package or packages.
For more information, see the DocLint section of the javadoc command documentation.
-Xlintโ Enables all recommended warnings. In this release, enabling all available warnings is recommended.-Xlint:[-]key(,[-]key)*โ Supplies warnings to enable or disable, separated by comma. Precede akeyby a hyphen (-) to disable the specified warning.
Supported values for key are:
allโ Enables all warnings.auxiliaryclassโ Warns about an auxiliary class that is hidden in a source file, and is used from other files.castโ Warns about the use of unnecessary casts.classfileโ Warns about the issues related to classfile contents.deprecationโ Warns about the use of deprecated items.dep-annโ Warns about the items marked as deprecated injavadocbut without the@Deprecatedannotation.divzeroโ Warns about the division by the constant integer0.emptyโ Warns about an empty statement afterif.exportsโ Warns about the issues regarding module exports.fallthroughโ Warns about the falling through from one case of aswitchstatement to the next.finallyโ Warns aboutfinallyclauses that do not terminate normally.lossy-conversionsโ Warns about possible lossy conversions in compound assignment.missing-explicit-ctorโ Warns about missing explicit constructors inpublicandprotectedclasses in exported packages.moduleโ Warns about the module system-related issues.opensโ Warns about the issues related to moduleopens.optionsโ Warns about the issues relating to use of command line options.output-file-clashโ Warns if any output file is overwritten during compilation. This can occur, for example, on case-insensitive filesystems.overloadsโ Warns about the issues related to method overloads.overridesโ Warns about the issues related to method overrides.pathโ Warns about the invalid path elements on the command line.previewโ Warns about the use of preview language features.processingโ Warns about the issues related to annotation processing.rawtypesโ Warns about the use of raw types.removalโ Warns about the use of an API that has been marked for removal.requires-automaticโ Warns developers about the use of automatic modules inrequiresclauses.requires-transitive-automaticโ Warns about automatic modules inrequires transitive.serialโ Warns about the serializable classes that do not provide a serial version ID. Also warns about access to non-publicmembers from a serializable element.staticโ Warns about accessing a static member using an instance.strictfpโ Warns about unnecessary use of thestrictfpmodifier.synchronizationโ Warns about synchronization attempts on instances of value-based classes.text-blocksโ Warns about inconsistent white space characters in text block indentation.this-escapeโ Warns about constructors leakingthisprior to subclass initialization.tryโ Warns about the issues relating to the use oftryblocks (that is, try-with-resources).uncheckedโ Warns about the unchecked operations.varargsโ Warns about the potentially unsafe vararg methods.noneโ Disables all warnings.
With the exception of all and none, the keys can be used with the @SuppressWarnings annotation to suppress warnings in a part of the source code being compiled.
See Examples of Using -Xlint keys.
-Xmaxerrsnumber โ Sets the maximum number of errors to print.-Xmaxwarnsnumber โ Sets the maximum number of warnings to print.-Xpkginfo:[always, legacy, nonempty]โ Specifies when and how thejavaccommand generatespackage-info.classfiles frompackage-info.javafiles using one of the following options:alwaysโ Generates apackage-info.classfile for everypackage-info.javafile. This option may be useful if you use a build system such as Ant, which checks that each.javafile has a corresponding.classfile.legacyโ Generates apackage-info.classfile only ifpackage-info.javacontains annotations. This option does not generate apackage-info.classfile ifpackage-info.javacontains only comments.
Note: A package-info.class file might be generated but be empty if all the annotations in the package-info.java file have RetentionPolicy.SOURCE.
nonemptyโ Generates apackage-info.classfile only ifpackage-info.javacontains annotations withRetentionPolicy.CLASSorRetentionPolicy.RUNTIME.
-Xplugin:name argsโ Specifies the name and optional arguments for a plug-in to be run. Ifargsare provided,nameandargsshould be quoted or otherwise escape the whitespace characters between thenameand all the arguments. For details on the API for a plugin, see the API documentation forjdk.compiler/com.sun.source.util.Plugin.-Xprefer:[source, newer]โ Specifies which file to read when both a source file and class file are found for an implicitly compiled class using one of the following options. See Searching for Module, Package and Type Declarations.-Xprefer:newerโ Reads the newer of the source or class files for a type (default).-Xprefer:sourceโ Reads the source file. Use-Xprefer:sourcewhen you want to be sure that any annotation processors can access annotations declared with a retention policy ofSOURCE.
-Xprintโ Prints a textual representation of specified types for debugging purposes. This does not perform annotation processing or compilation. The format of the output could change.-XprintProcessorInfoโ Prints information about which annotations a processor is asked to process.-XprintRoundsโ Prints information about initial and subsequent annotation processing rounds.-Xstdoutfilename โ Sends compiler messages to the named file. By default, compiler messages go toSystem.err.
๐ ENVIRONMENT VARIABLES ๐
๐ CLASSPATH ๐
If the --class-path option or any of its alternate forms are not specified, the class path will default to the value of the CLASSPATH environment variable if it is set. However, it is recommended that this environment variable should not be set, and that the --class-path option should be used to provide an explicit value for the class path when one is required.
๐ฆ JDK_JAVAC_OPTIONS ๐ฆ
The content of the JDK_JAVAC_OPTIONS environment variable, separated by white-spaces ( ) or white-space characters (\n, \t, \r, or \f) is prepended to the command line arguments passed to javac as a list of arguments.
The encoding requirement for the environment variable is the same as the javac command line on the system. JDK_JAVAC_OPTIONS environment variable content is treated in the same manner as that specified in the command line.
Single quotes (') or double quotes (") can be used to enclose arguments that contain whitespace characters. All content between the open quote and the first matching close quote are preserved by simply removing the pair of quotes. In case a matching quote is not found, the launcher will abort with an error message. @files are supported as they are specified in the command line. However, as in @files, use of a wildcard is not supported.
Examples of quoting arguments containing white spaces:
export JDK_JAVAC_OPTIONS='@"C:\white spaces\argfile"'
export JDK_JAVAC_OPTIONS='"@C:\white spaces\argfile"'
export JDK_JAVAC_OPTIONS='@C:\"white spaces"\argfile'
๐ COMMAND-LINE ARGUMENT FILES
Okay bestie, so you can literally put all your command-line options AND your source file names into one file โ any combo you want, no rules ๐ . Inside the file, the arguments just get separated by spaces or newline characters, easy peasy. Oh, and if a file name has spaces in it? Wrap the whole thing in double quotation marks and you're golden ๐.
Now here's the part you actually need to remember, so don't skip it ๐:
- File names inside an argument file are relative to the current directory, NOT to wherever the argument file itself is chilling. Big difference, fr fr.
- Wildcards (
*) are not allowed in these lists โ so no trying to sneak in*.java, it's not happening ๐. - Using the at sign (
@) to recursively interpret files? Not supported. Nope. - The
-Joptions are not supported here, because they get passed to the launcher, and the launcher doesn't do argument files. Periodt.
To actually use one, you run the javac command and hand over the path and name of each argument file with an at sign (@) in front. The moment javac sees an argument that starts with @, it expands that file's contents right into the argument list. Magic โจ.
๐๏ธ Examples of Using javac @filename
Single Argument File
You could just have one argument file named argfile holding all your javac arguments:
javac @argfile
And this file could literally contain the contents of both files from the Two Argument Files example below. Multitasking icon ๐
Two Argument Files
Or split it up: one file for the javac options, the other for the source file names. Heads up though โ these lists have no line-continuation characters ๐จ.
Make a file named options with this in it:
Linux and macOS:
-d classes
-g
-sourcepath /java/pubs/ws/1.3/src/share/classes
Windows:
-d classes
-g
-sourcepath C:\java\pubs\ws\1.3\src\share\classes
Then make a file named sources with this:
MyClass1.java
MyClass2.java
MyClass3.java
And run it like:
javac @options @sources
Chef's kiss ๐๐
Argument Files with Paths
Argument files can totally have paths, sure โ but any file names inside them are still relative to the current working directory (not path1 or path2, bestie, read carefully):
javac @path1/options @path2/sources
๐ธ ARRANGEMENT OF SOURCE CODE
So in the Java language, classes and interfaces can be organized into packages, and packages can be organized into modules โ it's giving organizational queen energy ๐. And javac expects that the physical arrangement of your source files in directories matches that organization: classes into packages, packages into modules. Mirror it or else ๐ช.
Widely adopted convention alert ๐: module names and package names begin with a lower-case letter, and class names begin with an upper-case letter. That's just the vibe, iykyk.
๐ Arrangement of Source Code for a Package
When classes and interfaces get organized into a package, the package is represented as a directory, and any subpackages are represented as subdirectories. Clean, simple, iconic โจ.
For example:
- The package
pis represented as a directory calledp. - The package
p.qโ that is, the subpackageqof packagepโ is represented as the subdirectoryqof directoryp. So the directory tree representing packagep.qis thereforep\qon Windows, andp/qon other systems. - The package
p.q.ris represented as the directory treep\q\r(on Windows) orp/q/r(on other systems).
Inside a directory or subdirectory, the .java files represent the classes and interfaces in that corresponding package or subpackage. Slay ๐.
For example:
- The class
Xdeclared in packagepis represented by the fileX.javain thepdirectory. - The class
Ydeclared in packagep.qis represented by the fileY.javain theqsubdirectory of directoryp. - The class
Zdeclared in packagep.q.ris represented by the fileZ.javain thersubdirectory ofp\q(on Windows) orp/q(on other systems).
And sometimes it's just convenient to split your code into separate directories โ each one structured exactly as described above โ and then hand javac the whole aggregate list of directories. Do what works for you, no judgment ๐ซถ.
๐ง Arrangement of Source Code for a Module
In the Java language, a module is a set of packages designed for reuse. Besides the .java files for classes and interfaces, every module has a source file called module-info.java which:
- declares the module's name;
- lists the packages exported by the module (to allow reuse by other modules);
- lists other modules required by the module (to reuse their exported packages).
So when packages get organized into a module, the module is represented by one or more directories representing the packages in the module โ and one of those contains the module-info.java file. It may be convenient (but it is not required!) to use a single directory, named after the module, to hold the module-info.java file alongside the directory tree representing the packages in the module (i.e., the package hierarchy described above). The exact arrangement of source code for a module is typically dictated by whatever conventions your development environment (IDE) or build system has adopted. Basically, follow the house rules ๐ .
For example:
- The module
a.b.cmay be represented by the directorya.b.c, on all systems. - The module's declaration is represented by the file
module-info.javain thea.b.cdirectory. - If the module contains package
p.q.r, then thea.b.cdirectory contains the directory treep\q\r(on Windows) orp/q/r(on other systems).
And heads up โ the development environment may prescribe some directory hierarchy between the directory named for the module and the source files to be read by javac ๐.
For example:
- The module
a.b.cmay be represented by the directorya.b.c - The module's declaration and the module's packages may be in some subdirectory of
a.b.c, such assrc\main\java(on Windows) orsrc/main/java(on other systems).
Nested directories, but make it fashion ๐
๐ธ CONFIGURING A COMPILATION ๐ธ
Okay bestie, this whole section is literally just "how do I tell javac to do a basic compile" โ the starter pack, the tutorial level, the vibes. Read it, it's giving essentials. ๐
Also โ peep Configuring the Module System later for the extra deets you need when you're compiling for a release of the platform that supports modules. Modules, modules, modules. You'll get it.
๐ Source Files
- Just tell it the source files on the command line. That's it. That's the whole step.
If there are no compilation errors, the corresponding class files will be placed in the output directory. (No errors = no drama, class files materialize. โจ)
Some systems may limit the amount you can put on a command line โ rude, honestly. To work around those limits, you can use argument files. ๐ค
When compiling code for modules, you can also specify source files indirectly, by using the --module or -m option. Sneaky but legal.
๐ Output Directory
- Use the
-doption to specify an output directory in which to put the compiled class files.
This will normally be organized in a package hierarchy, unless you are compiling source code from multiple modules, in which case it will be organized as a module hierarchy. Know the difference, it matters. ๐
When the compilation has been completed: if you are compiling one or more modules, you can place the output directory on the module path for the Java launcher; otherwise, you can place the output directory on the class path for the Java launcher.
Lowkey the whole game here: module-having code goes on the module path, everything else goes on the class path. Match the path to the vibe. ๐ฆ
๐ง Precompiled Code
The code to be compiled may refer to libraries beyond what is provided by the platform. If so, you must place these libraries on the class path or module path. If the library code is not in a module, place it on the class path; if it is in a module, place it on the module path. Yes, this is the same rule as above. Yes, it will be asked again. ๐ญ
--class-pathโ use it to specify libraries to be placed on the class path. Locations on the class path should be organized in a package hierarchy. You can also use alternate forms of the option:-classpathor-cp. Three names, one icon. ๐--module-pathโ use it to specify libraries to be placed on the module path. Locations on the module path should either be modules or directories of modules. You can also use an alternate form of the option:-p.
See Configuring the Module System for details on how to modify the default configuration of library modules.
Note: the options for the class path and module path are not mutually exclusive, although it is not common to specify the class path when compiling code for one or more modules. Nothing's stopping you, bestie โ it's just not the usual serve. ๐ซถ
๐ Additional Source Files
The code to be compiled may refer to types in additional source files that are not specified on the command line. If so, you must put those source files on either the source path or module path. And here's the catch: you can only specify one of these options. If you are not compiling code for a module, or if you are only compiling code for a single module, use the source path; if you are compiling code for multiple modules, use the module source path. Pick a lane. โจ
--source-pathโ use it to specify the locations of additional source files that may be read byjavac. Locations on the source path should be organized in a package hierarchy. You can also use an alternate form of the option:-sourcepath. (No extra-energy here, that's just how it is.)--module-source-pathโ use it one or more times to specify the location of additional source files in different modules that may be read byjavac, or when compiling source files in multiple modules. You can either specify the locations for each module individually, or you can organize the source files so that you can specify the locations all together. For more details, see The Module Source Path Option. Very choose-your-own-adventure. ๐ธ
If you want to be able to refer to types in additional source files but do not want them to be compiled, use the -implicit option. Ghosting them, essentially. ๐ป
Note: if you are compiling code for multiple modules, you must always specify a module source path, and all source files specified on the command line must be in one of the directories on the module source path, or in a subdirectory thereof. No exceptions, no wiggle room, no negotiating. ๐
โญ Example of Compiling Multiple Source Files
This example compiles the Aloha.java, GutenTag.java, Hello.java, and Hi.java source files in the greetings package. Iconic little multilingual friend group fr fr.
Linux and macOS:
% javac greetings/*.java
% ls greetings
Aloha.class GutenTag.class Hello.class Hi.class
Aloha.java GutenTag.java Hello.java Hi.java
Windows:
C:\>javac greetings\*.java
C:\>dir greetings
Aloha.class GutenTag.class Hello.class Hi.class
Aloha.java GutenTag.java Hello.java Hi.java
Look at all those .class files showing up next to the .java files. Compiler ate and left no crumbs. ๐ฅ
๐ฆ Example of Specifying a User Class Path
After changing one of the source files in the previous example, recompile it:
Linux and macOS:
pwd
/examples
javac greetings/Hi.java
Windows:
C:\>cd
\examples
C:\>javac greetings\Hi.java
Because greetings.Hi refers to other classes in the greetings package, the compiler needs to find these other classes. The previous example works because the default user class path is the directory that contains the package directory. So convenient. ๐
If you want to recompile this file without concern for which directory you are in, then add the examples directory to the user class path by setting CLASSPATH. This example uses the -classpath option.
Linux and macOS:
javac -classpath /examples /examples/greetings/Hi.java
Windows:
C:\>javac -classpath \examples \examples\greetings\Hi.java
If you change greetings.Hi to use a banner utility, then that utility also needs to be accessible through the user class path. New dependency, new entry, simple as that. ๐
Linux and macOS:
javac -classpath /examples:/lib/Banners.jar \
/examples/greetings/Hi.java
Windows:
C:\>javac -classpath \examples;\lib\Banners.jar ^
\examples\greetings\Hi.java
To execute a class in the greetings package, the program needs access to the greetings package, and to the classes that the greetings classes use. Because friendships are transitive, apparently. ๐ซถ
Linux and macOS:
java -classpath /examples:/lib/Banners.jar greetings.Hi
Windows:
C:\>java -classpath \examples;\lib\Banners.jar greetings.Hi
๐ CONFIGURING THE MODULE SYSTEM ๐
If you want to include additional modules in your compilation, use the --add-modules option. This may be necessary when you are compiling code that is not in a module, or which is in an automatic module, and the code refers to API in the additional modules. Basically: yes, the code needs them, so go fetch them. ๐ง
If you want to restrict the set of modules in your compilation, use the --limit-modules option. This may be useful if you want to ensure that the code you are compiling is capable of running on a system with a limited set of modules installed. Setting boundaries, honestly very healthy. โจ
If you want to break encapsulation and specify that additional packages should be considered as exported from a module, use the --add-exports option. This may be useful when performing white-box testing; relying on access to internal API in production code is strongly discouraged. Testing? Slay. Production? Absolutely not, bestie. ๐ญ
If you want to specify that additional packages should be considered as required by a module, use the --add-reads option. This may be useful when performing white-box testing; relying on access to internal API in production code is strongly discouraged. Same warning, same energy. ๐
You can patch additional content into any module using the --patch-module option. See Patching a Module for more details. โจ
๐ SEARCHING FOR MODULE, PACKAGE AND TYPE DECLARATIONS ๐
Okay so here's the situation bestie: to compile a source file, the compiler often needs info about a module or a type, but that declaration? Not in any of the source files you put on the command line. Rude, I know. ๐
javac needs type information for every class or interface that's used, extended, or implemented in the source file. And that includes classes and interfaces that aren't even explicitly mentioned in the source file, but that hand over info through inheritance. Sneaky little ancestors.
For example: when you create a subclass of java.awt.Window, you're also using the ancestor classes of Window: java.awt.Container, java.awt.Component, and java.lang.Object. Whole family tree showing up uninvited. ๐ญ
When compiling code for a module, the compiler also needs the declaration of that module available.
A successful search may produce a class file, a source file, or both. If both are found, then you can use the -Xprefer option to tell the compiler which one to use. Choose your fighter โจ
If a search finds and uses a source file, then by default javac compiles that source file. You can change this behavior with -implicit.
โ ๏ธ The compiler might not discover that it needs some type information until after annotation processing completes. So when the type info is found in a source file and no-implicitoption is specified, the compiler gives a warning that the file is being compiled without being subject to annotation processing. To disable the warning, either specify the file on the command line (so it will be subject to annotation processing) or use the-implicitoption to specify whether or not class files should be generated for such source files. No cap, that warning shows up a lot.
The way javac locates the declarations of those types depends on whether the reference exists within code for a module or not. Two whole different lanes. ๐ฃ๏ธ
๐๏ธ Searching Package Oriented Paths
When searching for a source or class file on a path made up of package oriented locations, javac checks each location on the path in turn for the possible presence of the file. The first occurrence of a particular file shadows (hides) any subsequent occurrences of like-named files. And this shadowing does not affect any search for files with a different name. So it's very much "first come, first served, everyone else stay in your lane."
This can be convenient when searching for source files, which may be grouped in different locations โ like shared code, platform-specific code, and generated code. It can also be useful when injecting alternate versions of a class file into a package, for debugging or other instrumentation reasons. But...
๐ ...it can also be dangerous โ like when you put incompatible different versions of a library on the class path. That's giving chaos energy and it will ruin your day.
๐ฆ Searching Module Oriented Paths
Before scanning any module paths for any package or type declarations, javac lazily scans the following paths and locations to figure out which modules will be used in the compilation:
- The module source path (see the
--module-source-pathoption) - The path for upgradeable modules (see the
--upgrade-module-pathoption) - The system modules (see the
--systemoption) - The user module path (see the
--module-pathoption)
For any module, the first occurrence of the module during the scan completely shadows (hides) any subsequent appearance of a like-named module. Same energy as the package path thing. ๐
While locating the modules, javac is able to determine the packages exported by the module and to associate with each module a package oriented path for the contents of the module. For any previously compiled module, this path will typically be a single entry for either a directory or a file that provides an internal directory-like hierarchy, such as a JAR file. So when searching for a type that's in a package that's known to be exported by a module, javac can locate the declaration directly and efficiently. Iconic efficiency, honestly. โก
๐ Searching for the Declaration of a Module
If the module has been previously compiled, the module declaration lives in a file named module-info.class in the root of the package hierarchy for the content of the module.
If the module is one of those currently being compiled, the module declaration will be either:
- the file named
module-info.classin the root of the package hierarchy for the module in the class output directory, or - the file named
module-info.javain one of the locations on the source path or on the module source path for the module.
๐ Searching for the Declaration of a Type When the Reference is not in a Module
When searching for a type that's referenced in code that is not in a module, javac will look in the following places:
- The platform classes (or the types in exported packages of the platform modules). (This is for compiled class files only.)
- Types in exported packages of any modules on the module path, if applicable. (This is for compiled class files only.)
- Types in packages on the class path and/or source path:
- If both are specified,
javaclooks for compiled class files on the class path and for source files on the source path. - If the class path is specified, but not the source path,
javaclooks for both compiled class files and source files on the class path. - If the class path is not specified, it defaults to the current directory.
- If both are specified,
When looking for a type on the class path and/or source path, if both a compiled class file and a source file are found, the most recently modified file will be used by default. If the source file is newer, it will be compiled and may override any previously compiled version of the file. You can use the -Xprefer option to override the default behavior. Bestie gets the final say ๐
๐งฉ Searching for the Declaration of a Type When the Reference is in a Module
When searching for a type that's referenced in code in a module, javac will examine the declaration of the enclosing module to determine if the type is in a package that's exported from another module that is readable by the enclosing module. If so, javac will simply and directly go to the definition of that module to find the definition of the required type. No detours, no side quests, straight to the point. ๐ฏ
Unless the module is another of the modules being compiled, javac will only look for compiled class files. In other words, javac will not look for source files in platform modules or modules on the module path. Lower those expectations fr fr.
If the type being referenced is not in some other readable module, javac will examine the module being compiled to try and find the declaration of the type. javac will look for the declaration of the type as follows:
- Source files specified on the command line or on the source path or module source path.
- Previously compiled files in the output directory.
๐๏ธ DIRECTORY HIERARCHIES ๐๏ธ
javac generally assumes that source files and compiled class files will be organized in a file system directory hierarchy, or in a type of file that supports an internal directory hierarchy, such as a JAR file. Three different kinds of hierarchy are supported: a package hierarchy, a module hierarchy, and a module source hierarchy. Three flavors, all valid, pick your vibe ๐
While javac is fairly relaxed about the organization of source code โ beyond the expectation that source will be organized in one or more package hierarchies โ and can generally accommodate organizations prescribed by development environments and build tools, Java tools in general, and javac and the Java launcher in particular, are more stringent regarding the organization of compiled class files. Those get organized in package hierarchies or module hierarchies, as appropriate. Class files do not get to be messy, sorry. ๐ค
The location of these hierarchies is specified to javac with command-line options whose names typically end in path, like --source-path or --class-path. And as a general rule, path options whose name includes the word module, like --module-path, are used to specify module hierarchies โ although some module-related path options allow a package hierarchy to be specified on a per-module basis. All other path options are used to specify package hierarchies. Naming conventions ate, honestly. โจ
๐ Package Hierarchy
In a package hierarchy, directories and subdirectories are used to represent the component parts of the package name, with the source file or compiled class file for a type being stored as a file with an extension of .java or .class in the most nested directory. Nested like a matryoshka doll ๐ช
For example, in a package hierarchy, the source file for a class com.example.MyClass will be stored in the file:
com/example/MyClass.java
๐๏ธ Module Hierarchy
In a module hierarchy, the first level of directories are named for the modules in the hierarchy; and within each of those directories, the contents of the module are organized in package hierarchies. Module folder, then package folders, all the way down. ๐
For example, in a module hierarchy, the compiled class file for a type called com.example.MyClass in a module called my.library will be stored in:
my.library/com/example/MyClass.class
The various output directories used by javac โ the class output directory, the source output directory, and the native header output directory โ will all be organized in a module hierarchy when multiple modules are being compiled. Every single one. Consistent queen behavior ๐
๐ธ Module Source Hierarchy
So even though the source for each individual module should always be organized in a package hierarchy, it may be convenient to group those hierarchies into a module source hierarchy. This is similar to a module hierarchy, except that there may be intervening directories between the directory for the module and the directory that is the root of the package hierarchy for the source code of the module. Little extra layers, no problem ๐ซถ
For example, in a module source hierarchy, the source file for a type called com.example.MyClass in a module called my.library may be stored in a file such as:
my.library/src/main/java/com/example/MyClass.java
๐ THE MODULE SOURCE PATH OPTION
Okay so the --module-source-path option has two forms, and they're lowkey different vibes:
- a module-specific form, where you hand it a package path for each module that has code to compile
- a module-pattern form, where the source path for each module is spelled out by a pattern
The module-specific form is generally simpler to use when you've only got a small number of modules. The module-pattern form is more convenient when the number of modules is large and they're organized in a regular manner that a pattern can describe. iykyk โจ
You can give multiple instances of the --module-source-path option, each one using either the module-pattern form or the module-specific form, but bestie, there are limits:
- the module-pattern form may be used at most once
- the module-specific form may be used at most once for any given module
And if the module-specific form is used for any module, the associated search path overrides any path that might otherwise have been inferred from the module-pattern form. No cap, it just wins. ๐
๐ Module-specific form
The module-specific form lets you give an explicit search path for any specific module. It's giving:
--module-source-path module-name=file-path (path-separator file-path)*
The path separator character is ; on Windows, and : otherwise.
Note: this is similar to the form used for the --patch-module option. ๐
๐ฆ Module-pattern form
The module-pattern form lets you specify the module source path concisely for any number of modules organized in a regular manner. Slay.
--module-source-path pattern
The pattern is defined by the following rules, applied in order:
- The argument is considered to be a series of segments separated by the path separator character (
;on Windows, and:otherwise). - Each segment containing curly braces of the form
string1{alt1 ( ,alt2 )* } string2
is considered to be replaced by a series of segments formed by "expanding" the braces:
string1 alt1 string2
string1 alt2 string2
and so on...
The braces may be nested ๐ช
This rule is applied for all such usages of braces.
- Each segment must have at most one asterisk (
*). If a segment does not contain an asterisk, it is considered to be as though the file separator character and an asterisk are appended.
For any module M, the source path for that module is formed from the series of segments obtained by substituting the module name M for the asterisk in each segment.
Note: in this context, the asterisk is just used as a special marker, to denote the position in the path of the module name. Do not confuse it with the use of * as a file name wildcard character, like the one found on most operating systems. Literally different things, bestie. ๐
๐ฉน PATCHING MODULES
javac allows any content โ whether in source or compiled form โ to be patched into any module using the --patch-module option. Why would you do this? Maybe you want to compile alternative implementations of a class to be patched at runtime into a JVM, or inject additional classes into the module, like when you're testing. Very main character energy.
The form of the option is:
--patch-module module-name=file-path (path-separator file-path )*
The path separator character is ; on Windows, and : otherwise. The paths given for the module must specify the root of a package hierarchy for the contents of the module.
The option may be given at most once for any given module. Any content on the path will hide any like-named content later in the path and in the patched module.
โ ๏ธ When patching source code into more than one module, the --module-source-path must also be used, so that the output directory is organized in a module hierarchy, and capable of holding the compiled class files for the modules being compiled. Don't skip this step, fr fr.
โจ ANNOTATION PROCESSING
The javac command provides direct support for annotation processing. Obsessed.
The API for annotation processors is defined in the javax.annotation.processing and javax.lang.model packages and subpackages.
๐ How Annotation Processing Works
Unless annotation processing is disabled with the -proc:none option, the compiler searches for any annotation processors that are available. The search path can be specified with the -processorpath option. If no path is specified, then the user class path is used. Processors are located by means of service provider-configuration files named META-INF/services/javax.annotation.processing.Processor on the search path. Such files should contain the names of any annotation processors to be used, listed one per line. Alternatively, processors can be specified explicitly, using the -processor option.
After scanning the source files and classes on the command line to determine what annotations are present, the compiler queries the processors to determine what annotations they process. When a match is found, the processor is called. A processor can claim the annotations it processes, in which case no further attempt is made to find any processors for those annotations. After all of the annotations are claimed, the compiler does not search for additional processors. Periodt.
If any processors generate new source files, then another round of annotation processing occurs: any newly generated source files are scanned, and the annotations processed as before. Any processors called on previous rounds are also called on all subsequent rounds. This continues until no new source files are generated. ๐
After a round occurs where no new source files are generated, the annotation processors are called one last time, to give them a chance to complete any remaining work. Finally, unless the -proc:only option is used, the compiler compiles the original and all generated source files.
If you use an annotation processor that generates additional source files to be included in the compilation, you can specify a default module to be used for the newly generated files โ for use when a module declaration is not also generated. In this case, use the --default-module-for-created-files option. ๐
๐ธ Compilation Environment and Runtime Environment.
The declarations in source files and previously compiled class files are analyzed by javac in a compilation environment that is distinct from the runtime environment used to execute javac itself. And like โ yes, there's a deliberate similarity between many javac options and like-named options for the Java launcher, such as --class-path, --module-path and so on, but it is important to understand that in general the javac options just affect the environment in which the source files are compiled, and do not affect the operation of javac itself. Two different worlds, bestie. ๐
The distinction between the compilation environment and runtime environment is significant when it comes to using annotation processors. Although annotation processors process elements (declarations) that exist in the compilation environment, the annotation processor itself is executed in the runtime environment. If an annotation processor has dependencies on libraries that are not in modules, the libraries can be placed, along with the annotation processor itself, on the processor path. (See the --processor-path option.) If the annotation processor and its dependencies are in modules, you should use the processor module path instead. (See the --processor-module-path option.) When those are insufficient, it may be necessary to provide further configuration of the runtime environment. This can be done in two ways:
- If
javacis invoked from the command line, options can be passed to the underlying runtime by prefixing the option with-J. - You can start an instance of a Java Virtual Machine directly and use command line options and API to configure an environment in which
javaccan be invoked via one of its APIs.
โณ COMPILING FOR EARLIER RELEASES OF THE PLATFORM
javac can compile code that is to be used on other releases of the platform, using either the --release option, or the --source/-source and --target/-target options, together with additional options to specify the platform classes.
Depending on the desired platform release, there are some restrictions on some of the options that can be used. Vibe check time:
- When compiling for JDK 8 and earlier releases, you cannot use any option that is intended for use with the module system. This includes all of the following options:
--module-source-path,--upgrade-module-path,--system,--module-path,--add-modules,--add-exports,--add-opens,--add-reads,--limit-modules,--patch-module
If you use the --source/-source or --target/-target options, you should also set the appropriate platform classes using the boot class path family of options.
- When compiling for JDK 9 and later releases, you cannot use any option that is intended to configure the boot class path. This includes all of the following options:
-Xbootclasspath/p:,-Xbootclasspath,-Xbootclasspath/a:,-endorseddirs,-Djava.endorsed.dirs,-extdirs,-Djava.ext.dirs,-profile
If you use the --source/-source or --target/-target options, you should also set the appropriate platform classes using the --system option to give the location of an appropriate installed release of JDK.
๐จ When using the --release option, only the supported documented API for that release may be used โ you cannot use any options to break encapsulation to access any internal classes. No sneaky sneaky.
๐ซถ APIS
The javac compiler can be invoked using an API in three different ways:
The Java Compiler API
This provides the most flexible way to invoke the compiler, including the ability to compile source files provided in memory buffers or other non-standard file systems. Iconic.
The ToolProvider API
A ToolProvider for javac can be obtained by calling ToolProvider.findFirst("javac"). This returns an object with the equivalent functionality of the command-line tool.
Note: This API should not be confused with the like-named API in the javax.tools package. ๐
The javac Legacy API
This API is retained for backward compatibility only. All new code should use either the Java Compiler API or the ToolProvider API. It's giving "still here but please move on".
Note: All other classes and methods found in a package with names that start withcom.sun.tools.javac(subpackages ofcom.sun.tools.javac) are strictly internal and subject to change at any time. Do not build your whole personality on them. ๐
๐ฅ EXAMPLES OF USING -XLINT KEYS
cast โ Warns about unnecessary and redundant casts, for example:
String s = (String) "Hello!"
classfile โ Warns about issues related to class file contents.
deprecation โ Warns about the use of deprecated items. For example:
โฆand hereโs the rest of that deprecation moment, bestie:
java.util.Date myDate = new java.util.Date();
int currentDay = myDate.getDay();
The method java.util.Date.getDay has been deprecated since JDK 1.1.
โจ dep-ann โจ
This one warns about items that are documented with the @deprecated Javadoc comment, but do not have the @Deprecated annotation. Itโs giving โtalk is cheap, whereโs the annotation?โ energy. Example:
/**
* @deprecated As of Java SE 7, replaced by {@link #newMethod()}
*/
public static void deprecatedMethod() { }
public static void newMethod() { }
๐
divzero ๐
Warns about division by the constant integer 0. Like, maโam, that is not math, that is chaos. Example:
int divideByZero = 42 / 0;
๐ empty ๐
Warns about empty statements after if statements. Example:
class E {
void m() {
if (true) ;
}
}
๐ฅ fallthrough ๐ฅ
Checks the switch blocks for fall-through cases and provides a warning message for any that are found. Fall-through cases are cases in a switch block, other than the last case in the block, whose code does not include a break statement, allowing code execution to fall through from that case to the next case. For example, the code following the case 1 label in this switch block does not end with a break statement:
switch (x) {
case 1:
System.out.println("1");
// No break statement here.
case 2:
System.out.println("2");
}
If the -Xlint:fallthrough option was used when compiling this code, then the compiler emits a warning about possible fall-through into case, with the line number of the case in question.
๐ฆ finally ๐ฆ
Warns about finally clauses that cannot be completed normally. Example:
public static int m() {
try {
throw new NullPointerException();
} catch (NullPointerException(); {
System.err.println("Caught NullPointerException.");
return 1;
} finally {
return 0;
}
}
The compiler generates a warning for the finally block in this example. When the int method is called, it returns a value of 0. A finally block executes when the try block exits. In this example, when control is transferred to the catch block, the int method exits. However, the finally block must execute, so itโs executed, even though control was transferred outside the method.
๐ธ options ๐ธ
Warns about issues related to the use of command-line options. See Compiling for Earlier Releases of the Platform.
๐ overrides ๐
Warns about issues related to method overrides. For example, consider the following two classes:
public class ClassWithVarargsMethod {
void varargsMethod(String... s) { }
}
public class ClassWithOverridingMethod extends ClassWithVarargsMethod {
@Override
void varargsMethod(String[] s) { }
}
The compiler generates a warning similar to the following:
warning: [override] varargsMethod(String[]) in ClassWithOverridingMethod
overrides varargsMethod(String...) in ClassWithVarargsMethod; overriding
method is missing '...'
When the compiler encounters a varargs method, it translates the varargs formal parameter into an array. In the method ClassWithVarargsMethod.varargsMethod, the compiler translates the varargs formal parameter String... s to the formal parameter String[] s, an array that matches the formal parameter of the method ClassWithOverridingMethod.varargsMethod. Consequently, this example compiles.
๐ path ๐
Warns about invalid path elements and nonexistent path directories on the command line (with regard to the class path, the source path, and other paths). Such warnings cannot be suppressed with the @SuppressWarnings annotation. For example:
- Linux and macOS:
javac -Xlint:path -classpath /nonexistentpath Example.java - Windows:
javac -Xlint:path -classpath C:\nonexistentpath Example.java
โญ processing โญ
Warns about issues related to annotation processing. The compiler generates this warning when you have a class that has an annotation, and you use an annotation processor that cannot handle that type of annotation. For example, the following is a simple annotation processor:
Source file AnnoProc.java:
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes("NotAnno")
public class AnnoProc extends AbstractProcessor {
public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv){
return true;
}
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}
Source file AnnosWithoutProcessors.java:
@interface Anno { }
@Anno
class AnnosWithoutProcessors { }
The following commands compile the annotation processor AnnoProc, then run this annotation processor against the source file AnnosWithoutProcessors.java:
javac AnnoProc.java
javac -cp . -Xlint:processing -processor AnnoProc -proc:only AnnosWithoutProcessors.java
When the compiler runs the annotation processor against the source file AnnosWithoutProcessors.java, it generates the following warning:
warning: [processing] No processor claimed any of these annotations: Anno
To resolve this issue, you can rename the annotation defined and used in the class AnnosWithoutProcessors from Anno to NotAnno.
๐ rawtypes ๐
Warns about unchecked operations on raw types. The following statement generates a rawtypes warning:
void countElements(List l) { ... }
The following example does not generate a rawtypes warning:
void countElements(List<?> l) { ... }
List is a raw type. However, List<?> is an unbounded wildcard parameterized type. Because List is a parameterized interface, always specify its type argument. In this example, the List formal argument is specified with an unbounded wildcard (?) as its formal type parameter, which means that the countElements method can accept any instantiation of the List interface.
๐ serial ๐
Warns about missing serialVersionUID definitions on serializable classes. For example:
public class PersistentTime implements Serializable
{
private Date time;
public PersistentTime() {
time = Calendar.getInstance().getTime();
}
public Date getTime() {
return time;
}
}
The compiler generates the following warning:
warning: [serial] serializable class PersistentTime has no definition of
serialVersionUID
If a serializable class does not explicitly declare a field named serialVersionUID, then the serialization runtime environment calculates a default serialVersionUID value for that class based on various aspects of the class, as described in the Java Object Serialization Specification. However, itโs strongly recommended that all serializable classes explicitly declare serialVersionUID values because the default process of computing serialVersionUID values is highly sensitive to class details that can vary depending on compiler implementations. As a result, this might cause an unexpected InvalidClassExceptions during deserialization. To guarantee a consistent serialVersionUID value across different Java compiler implementations, a serializable class must declare an explicit serialVersionUID value.
๐ง static ๐ง
Warns about issues relating to the use of static variables. For example:
class XLintStatic {
static void m1() { }
void m2() { this.m1(); }
}
The compiler generates the following warning:
warning: [static] static method should be qualified by type name,
XLintStatic, instead of by an expression
To resolve this issue, you can call the static method m1 as follows:
XLintStatic.m1();
Alternately, you can remove the static keyword from the declaration of the method m1.
๐ซถ this-escape ๐ซถ
Warns about constructors leaking this prior to subclass initialization. For example, this class:
public class MyClass {
public MyClass() {
System.out.println(this.hashCode());
}
}
generates the following warning:
MyClass.java:3: warning: [this-escape] possible 'this' escape
before subclass is fully initialized
System.out.println(this.hashCode());
^
A 'this' escape warning is generated when a constructor does something that might result in a subclass method being invoked before the constructor returns. In such cases the subclass method would be operating on an incompletely initialized instance. In the above example, a subclass of MyClass that overrides hashCode() to incorporate its own fields would likely produce an incorrect result when invoked as shown.
Warnings are only generated if a subclass could exist that is outside of the current module (or package, if no module) being compiled. So, for example, constructors in final and non-public classes do not generate warnings.
tryโ bestie this one's watching yourtryblocks, including try-with-resources statements ๐. Like, if you declare a resource and then just... don't use it? Warning. Case in point, this iconic little situation right here gets flagged because the resourceacdeclared in thetryblock is literally never used:
try ( AutoCloseable ac = getResource() ) { // do nothing}
uncheckedโ this key gives you the detailed tea on unchecked conversion warnings, the ones the Java Language Specification says are mandatory. Example:
List l = new ArrayList<Number>();
List<String> ls = l; // unchecked warning
So during type erasure, the types ArrayList<Number> and List<String> become ArrayList and List, respectively. That's the whole plot twist โจ
The ls command has the parameterized type List<String>. When the List referenced by l is assigned to ls, the compiler generates an unchecked warning. At compile time, the compiler and JVM cannot determine whether l refers to a List<String> type. In this case, l does not refer to a List<String> type. As a result, heap pollution occurs ๐ญ
A heap pollution situation occurs when the List object l, whose static type is List<Number>, is assigned to another List object, ls, that has a different static type, List<String>. However, the compiler still allows this assignment. It must allow this assignment to preserve backward compatibility with releases of Java SE that do not support generics. Because of type erasure, List<Number> and List<String> both become List. Consequently, the compiler allows the assignment of the object l, which has a raw type of List, to the object ls. It's giving "we're legally required to let you do this" ๐
varargsโ warns you about unsafe use of variable arguments (varargs) methods, especially the ones carrying non-reifiable arguments. Example time:
public class ArrayBuilder {
public static <T> void addToList (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
}
A non-reifiable type is a type whose type information is not fully available at runtime. No cap ๐ซถ
The compiler generates the following warning for the definition of the method ArrayBuilder.addToList:
warning: [varargs] Possible heap pollution from parameterized vararg type T
When the compiler encounters a varargs method, it translates the varargs formal parameter into an array. However, the Java programming language does not permit the creation of arrays of parameterized types. In the method ArrayBuilder.addToList, the compiler translates the varargs formal parameter T... elements to the formal parameter T[] elements, an array. However, because of type erasure, the compiler converts the varargs formal parameter to Object[] elements. Consequently, there's a possibility of heap pollution. Skincare routine: cleanse, tone, erase your types, moisturize ๐ธ
Okay bestie, that is genuinely the whole page โ every last flag, caveat, and warning preserved with love and zero facts harmed in the making ๐ Go compile something iconic.
That's a wrap on JAVAC(1) โ brought to you by JDK 21, dated 2023, source line and all, and signed off with so much love ๐โจ๐ฆ
๐ฆ where this page comes from
- centos-stream 10: java-21-openjdk-devel-slowdebug 1:21.0.12.1.1-2.1.el10 ยท ASL 1.1 and ASL 2.0 and BSD and BSD with advertising and GPL+ and GPLv2 and GPLv2 with exceptions and IJG and LGPLv2+ and MIT and MPLv2.0 and Public Domain and W3C and zlib and ISC and FTL and RSA
- Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms