Java Language Specification — Basic Syntax
Source: https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html
1. Spec Reference
- JLS Chapter 3: Lexical Structure — https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html
- JLS Chapter 7: Program Structure — https://docs.oracle.com/javase/specs/jls/se21/html/jls-7.html
- JLS Chapter 8: Class Declarations — https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html
- JLS §3.1: Unicode — Input elements and line terminators
- JLS §3.4: Line Terminators
- JLS §3.5: Input Elements and Tokens
- JLS §3.6: White Space
- JLS §3.7: Comments
- JLS §3.8: Identifiers
- JLS §3.9: Keywords
- JLS §7.3: Compilation Units
- JLS §7.4: Package Declarations
- JLS §7.5: Import Declarations
- JLS §8.1: Class Declarations
-- JLS §7.3: Compilation Units --
CompilationUnit:
OrdinaryCompilationUnit
ModularCompilationUnit
OrdinaryCompilationUnit:
[PackageDeclaration] {ImportDeclaration} {TopLevelClassOrInterfaceDeclaration}
ModularCompilationUnit:
{ImportDeclaration} ModuleDeclaration
-- JLS §7.4: Package Declaration --
PackageDeclaration:
{PackageModifier} package PackageName ;
PackageName:
Identifier
PackageName . Identifier
-- JLS §7.5: Import Declarations --
ImportDeclaration:
SingleTypeImportDeclaration
TypeImportOnDemandDeclaration
SingleStaticImportDeclaration
StaticImportOnDemandDeclaration
SingleTypeImportDeclaration:
import TypeName ;
TypeImportOnDemandDeclaration:
import PackageOrTypeName . * ;
-- JLS §8.1: Class Declaration --
ClassDeclaration:
NormalClassDeclaration
EnumDeclaration
RecordDeclaration
NormalClassDeclaration:
{ClassModifier} class TypeIdentifier [TypeParameters]
[ClassExtends] [ClassImplements] [ClassPermits] ClassBody
ClassModifier:
Annotation
public | protected | private
abstract | static | final | sealed | non-sealed | strictfp
-- JLS §3.8: Identifiers --
Identifier:
IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
IdentifierChars:
JavaLetter {JavaLetterOrDigit}
JavaLetter:
any Unicode character that is a "Java letter"
JavaLetterOrDigit:
any Unicode character that is a "Java letter-or-digit"
-- JLS §3.9: Keywords --
Keyword:
ReservedKeyword | ContextualKeyword
ReservedKeyword: one of
abstract continue for new switch
assert default if package synchronized
boolean do goto private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const float native super while
_
-- JLS §3.7: Comments --
Comment:
TraditionalComment
EndOfLineComment
TraditionalComment:
/* CommentTail
CommentTail:
* CommentTailStar
NotStar CommentTail
EndOfLineComment:
// {InputCharacter}
-- JLS §3.4: Line Terminators --
LineTerminator:
the ASCII LF character, also known as "newline"
the ASCII CR character, also known as "return"
the ASCII CR character followed by the ASCII LF character
-- JLS §3.6: White Space --
WhiteSpace:
the ASCII SP character, also known as "space"
the ASCII HT character, also known as "horizontal tab"
the ASCII FF character, also known as "form feed"
LineTerminator
-- JLS §8.4: Method Declarations --
MethodDeclaration:
{MethodModifier} MethodHeader MethodBody
MethodHeader:
Result MethodDeclarator [Throws]
TypeParameters {Annotation} Result MethodDeclarator [Throws]
MethodDeclarator:
Identifier ( [FormalParameterList] ) [Dims]
MethodModifier:
Annotation
public | protected | private
abstract | static | final | synchronized | native | strictfp
-- JLS §3.10: Literals --
Literal:
IntegerLiteral
FloatingPointLiteral
BooleanLiteral
CharacterLiteral
StringLiteral
TextBlock
NullLiteral
3. Core Rules & Constraints
3.1 Source File Structure (JLS §7.3)
- A Java source file must end with
.java extension (by convention; not enforced by spec). - Each ordinary compilation unit may have at most one public top-level type.
- The file name must match the public type name (enforced by most compilers per JLS §7.6).
- Compilation units belong to a named package or the unnamed package.
3.2 Identifier Rules (JLS §3.8)
- Identifiers are unlimited in length.
- Must start with a
JavaLetter (Unicode letter, $, or _). - Subsequent characters may be
JavaLetterOrDigit. _ alone is a reserved keyword in Java 9+ (JLS §3.9, JEP 302). - Identifiers are case-sensitive:
myVar and MyVar are distinct. - Cannot be a reserved keyword, boolean literal (
true, false), or null.
- Comments are not tokens and are not significant to syntax.
/* */ comments do not nest: /* /* */ */ — the second */ is outside any comment. - JavaDoc comments (
/** */) are a special form of traditional comments. - Line comments (
//) extend to end of line only.
3.4 Class Declaration Rules (JLS §8.1)
- A class body
{} is mandatory even if empty. public classes must match the compilation unit file name. - At most one of
final, sealed, or non-sealed may appear on a class. abstract and final cannot both be present (JLS §8.1.1.1). - The
strictfp modifier is obsolete since Java 17 (JEP 306) but still syntactically valid.
3.5 Method Declaration Rules (JLS §8.4)
- Every method must have a return type or
void. main entry point: public static void main(String[] args) (pre-Java 21). - Java 21 introduces unnamed main method via JEP 445 (preview):
void main(). - Methods cannot be declared both
abstract and private, static, final, native, synchronized.
3.6 Package Declaration Rules (JLS §7.4)
- At most one package declaration per compilation unit.
- Package declaration must precede all import declarations and type declarations.
- Unnamed package cannot have a package declaration.
- Package names follow naming convention: all lowercase, domain-reversed.
4. Type Rules
4.1 Top-Level Type Accessibility
- A top-level class/interface can only be
public or package-private (default). protected and private are not valid for top-level types (JLS §8.1.1).
4.2 Type Identifier Constraints
- Type identifiers (JLS §3.8) must not be a
RestrictedIdentifier: var, record, yield, sealed, permits, when. var is a reserved type name since Java 10 (JEP 286) — cannot be used as a class name.
4.3 Class Hierarchy
- Every class implicitly extends
java.lang.Object unless it explicitly extends another class (JLS §8.1.4). Object itself has no superclass. - Circular inheritance is a compile-time error (JLS §8.1.4).
5. Behavioral Specification
5.1 Program Execution (JLS §12.1)
- JVM loads the initial class specified by the launcher.
- JVM links (verifies, prepares, resolves) the class.
- JVM initializes the class (runs static initializers).
- JVM invokes
main(String[]). - Execution proceeds from
main. - Program terminates when all non-daemon threads finish or
System.exit() is called.
5.2 Lexical Translation (JLS §3.2)
Java programs are translated in phases: 1. Unicode escape sequences (\uXXXX) are translated first. 2. Input is divided into lines using line terminators. 3. Lines are divided into tokens (lexical analysis). 4. Tokens are parsed (syntax analysis).
5.3 Unicode Escapes (JLS §3.3)
\uXXXX can appear anywhere in source code (including identifiers). - Multiple
us are allowed: \uuuu0041 is valid and equals A. - Unicode escapes are processed before any other lexical processing.
6. Defined vs Undefined Behavior
| Situation | Behavior per JLS |
File has no main method | Compile succeeds; runtime NoSuchMethodError or launcher error |
| Duplicate class in same package | Compile-time error (JLS §7.6) |
| Identifier same as contextual keyword | Allowed (e.g., var as variable name is NOT allowed since Java 10) |
/* */ nested comment | Outer ends at first */; inner /* is ignored |
\u000A in string literal | Line terminator in source → compile-time error (JLS §3.10.5) |
\u0022 in string literal | Allowed — translates to " before parsing |
Class named _ | Compile-time error since Java 9 (JLS §3.9) |
7. Edge Cases from Spec
7.1 Unicode Escape in Identifiers
// Legal: \u0041 is 'A'
int \u0041 = 10; // declares int A = 10;
7.2 _ as Identifier
// Java 8: legal (deprecated)
int _ = 5;
// Java 9+: compile-time error — _ is a keyword
/* This comment ends here: */
// The */ above ends the comment; "here:" and */ are outside
7.4 Multiple Public Classes in One File
// Compile-time error if two public classes in one file:
public class A {}
public class B {} // error: class B is public, should be in file B.java
7.5 strictfp on Classes (Java 17+)
// Java 17+ (JEP 306): all code is effectively strictfp
// strictfp modifier is obsolete but not an error
strictfp class Calculator { } // compiles with warning
7.6 Package-Private Top-Level Class
// No access modifier = package-private (not private)
class Helper { } // accessible only within the same package
8. Version History
| Java Version | Change | JEP/JLS Reference |
| Java 1.0 | Basic syntax established | JLS 1st ed. |
| Java 5 (1.5) | Generics, annotations, enhanced for, varargs, enums, autoboxing | JSR 14, 175 |
| Java 7 | Binary literals, underscores in literals, try-with-resources, diamond | JEP 334 (backport) |
| Java 8 | Lambda expressions, default methods, method references | JEP 126 |
| Java 9 | Module system; _ becomes reserved keyword | JEP 261, 302 |
| Java 10 | var local variable type inference | JEP 286 |
| Java 14 | Records (preview); pattern matching instanceof (preview) | JEP 359, 305 |
| Java 15 | Text blocks (standard) | JEP 378 |
| Java 16 | Records (standard); instanceof pattern (standard) | JEP 395, 394 |
| Java 17 | Sealed classes (standard); strictfp obsolete | JEP 409, 306 |
| Java 21 | Virtual threads; unnamed classes & instance main (preview) | JEP 444, 445 |
9. Implementation-Specific Behavior (JVM-Specific)
- Compiled
.class files follow the JVM Specification Chapter 4 format. javac produces class files with a magic number 0xCAFEBABE. - Java 21 class files have major version
65 (0x0041).
9.2 Compiler Behavior
javac may add synthetic methods/fields (e.g., access$000 for inner class access). - The compiler is free to reorder field initializations within static initializer blocks.
- Dead code elimination is performed but not guaranteed to match any specific strategy.
9.3 JVM Entry Point
- The JVM launcher searches for
public static void main(String[]) by default. - Java 21 preview (JEP 445): unnamed classes with
void main() are supported by java --enable-preview.
9.4 Encoding
javac defaults to the platform encoding unless -encoding is specified. - Source files are recommended to be UTF-8 (mandatory for unnamed classes in Java 21 preview).
10. Spec Compliance Checklist
11. Official Examples (Compilable Java 21 Code)
// Example 1: Minimal Java Program
// File: HelloWorld.java
package com.example.basics;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
// Example 2: Package, Imports, Multiple Classes
// File: Greeter.java
package com.example.basics;
import java.util.List;
import java.util.ArrayList;
import static java.lang.Math.PI;
public class Greeter {
private String name;
public Greeter(String name) {
this.name = name;
}
public String greet() {
return "Hello, " + name + "!";
}
public static void main(String[] args) {
Greeter g = new Greeter("Java 21");
System.out.println(g.greet());
System.out.println("PI = " + PI);
List<String> items = new ArrayList<>();
items.add("alpha");
items.add("beta");
for (String item : items) {
System.out.println(item);
}
}
}
// Package-private helper class in same file
class InternalHelper {
static String format(String s) {
return "[" + s + "]";
}
}
// Example 3: Comments, Identifiers, Unicode
// File: SyntaxDemo.java
public class SyntaxDemo {
// Single-line comment
/* Multi-line
comment */
/**
* JavaDoc comment
* @param args command line arguments
*/
public static void main(String[] args) {
// Unicode escape in identifier
int caf\u00E9 = 42; // declares: int café = 42;
System.out.println(caf\u00E9); // prints: 42
// var type inference (Java 10+)
var message = "Inferred as String";
System.out.println(message);
// Text block (Java 15+)
String json = """
{
"key": "value"
}
""";
System.out.println(json);
}
}
// Example 4: Sealed Class Hierarchy (Java 17+)
// File: Shape.java
public sealed class Shape permits Circle, Rectangle {
abstract double area();
}
final class Circle extends Shape {
private final double radius;
Circle(double radius) { this.radius = radius; }
@Override
double area() { return Math.PI * radius * radius; }
}
final class Rectangle extends Shape {
private final double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
double area() { return width * height; }
}
// Example 5: Record Declaration (Java 16+)
// File: Point.java
public record Point(double x, double y) {
// Compact constructor
public Point {
if (Double.isNaN(x) || Double.isNaN(y)) {
throw new IllegalArgumentException("Coordinates cannot be NaN");
}
}
public double distanceTo(Point other) {
double dx = this.x - other.x;
double dy = this.y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
public static void main(String[] args) {
Point p1 = new Point(0.0, 0.0);
Point p2 = new Point(3.0, 4.0);
System.out.println("Distance: " + p1.distanceTo(p2)); // 5.0
}
}
| Section | Topic | URL |
| JLS §3 | Lexical Structure | https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html |
| JLS §4 | Types, Values, Variables | https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html |
| JLS §6 | Names | https://docs.oracle.com/javase/specs/jls/se21/html/jls-6.html |
| JLS §7 | Packages and Modules | https://docs.oracle.com/javase/specs/jls/se21/html/jls-7.html |
| JLS §8 | Classes | https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html |
| JLS §9 | Interfaces | https://docs.oracle.com/javase/specs/jls/se21/html/jls-9.html |
| JLS §12 | Execution | https://docs.oracle.com/javase/specs/jls/se21/html/jls-12.html |
| JVMS §4 | Class File Format | https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html |
| JEP 445 | Unnamed Classes (Preview) | https://openjdk.org/jeps/445 |
| JEP 409 | Sealed Classes | https://openjdk.org/jeps/409 |