Lexical Structure and Style
|
This section documents the current Java release line, with Java 25 LTS as the reference point (no specific patch version is pinned), as published at the Java developer portal, the Java Tutorials, and the Java SE API specification — which are the references these pages are written and verified against. This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
A Java source file is plain Unicode text made of tokens — identifiers, keywords, literals, separators, and operators — laid out in a fixed structure. This page follows JLS chapter 3, "Lexical Structure" and the Java Tutorials "Language Basics" lesson.
Source-File Structure
A conventional source file has three parts in order: an optional package declaration, then any
import declarations, then one or more top-level type declarations.
// File: src/com/example/orders/Invoice.java
package com.example.orders; // 1. at most one package declaration, and it comes first
import java.time.LocalDate; // 2. imports: single-type imports read best
import java.util.List;
import static java.util.Objects.requireNonNull; // a static import brings in a static member
public class Invoice { // 3. exactly one public top-level type per file
private final LocalDate date = LocalDate.now();
private final List<LineItem> items;
public Invoice(List<LineItem> items) {
this.items = requireNonNull(items);
}
}
class LineItem { } // extra non-public top-level types are allowed here
The rules:
-
At most one
publictop-level type per file, and if there is one, the file name must match it exactly —Invoice.javaforpublic class Invoice. Additional package-private types may share the file, though one type per file is the usual style. -
The package name mirrors the directory path (
com/example/orders/Invoice.java). A file with nopackageline is in the unnamed package — fine for throwaway code, not for anything shared. -
import a.b.C;imports a single type;import a.b.*;imports every type in packagea.b(not its sub-packages).import static a.b.C.m;imports a static member so it can be used unqualified — the example above does this withObjects.requireNonNull. -
Source is Unicode — UTF-8 by default — and a
\uXXXXescape may appear anywhere in the file, not just in string literals.
A package groups related types and forms a namespace; see Packages and Modules. The current release line also allows a compact source file with no class declaration at all — see Getting Started.
Identifiers, Keywords, and Comments
An identifier names a variable, method, class, or package. It may contain Unicode letters, digits,
, and $, and must not start with a digit. $ and a leading are legal but reserved by
convention for machine-generated code.
int count; // fine
double _rate; // legal, discouraged
var café = "☕"; // any Unicode letter is allowed
int 2fast; // ERROR: identifier cannot start with a digit
Reserved words (JLS 3.9, also listed in the Java Tutorials keyword list) can never be used as identifiers:
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
* const and goto are reserved but unused. true, false and null are reserved literal values.
Contextual keywords — var, yield, record, sealed, permits, non-sealed, when, and the
module-declaration words (module, requires, exports, opens, uses, provides, to, with,
transitive, open) — act as keywords only inside the construct that needs them and remain valid
identifiers everywhere else, so pre-existing code that used record as a variable name still compiles.
Literals denote fixed values: integers (42, 0xFF, 0b1010), floating-point (3.14, 6e23),
char ('A'), String ("hi"), text blocks ("""), and true / false / null. Their exact
syntax is on Primitive Types and Variables.
Java has three comment forms; see JLS 3.7:
// a line comment runs to the end of the line
/* a block comment
can span several lines */
/**
* A Javadoc comment documents the element that follows it.
* @param name the recipient's display name
* @return a greeting line
*/
public String greet(String name) {
return "Hi, " + name;
}
Only Javadoc /** */ comments are processed by the javadoc tool into API documentation.
Statements, Blocks, and Whitespace
A statement is a unit of execution terminated by a semicolon. A block \{ … } groups zero or more
statements, can appear wherever a statement can, and introduces a scope for the locals declared in it.
int x = 1; // an expression statement
x++; // another
{ // a block: its own scope
int y = x + 1;
System.out.println(y);
} // y is not visible past here
; // an empty statement is legal (and usually a mistake)
The semicolon — not the newline — ends a statement, so one statement may span many lines and several statements may share one line. Whitespace (spaces, tabs, newlines) separates tokens where needed but is otherwise insignificant: indentation is for readers, and the compiler ignores it. This is unlike Python, where indentation is syntactically meaningful.
Naming and Code Conventions
The community follows one broadly shared style. Rather than restate it, this section shows it once; the authoritative source is Oracle’s Java Code Conventions, assumed throughout this section.
package com.example.billing; // packages: all lowercase, reverse-domain, dotted
public class InvoicePrinter { // types: UpperCamelCase (a.k.a. PascalCase)
public static final int MAX_RETRIES = 3; // constants (static final): UPPER_SNAKE_CASE
private int retryCount; // fields / locals / parameters: lowerCamelCase
public void printInvoice(Invoice invoice) { // methods: lowerCamelCase, usually a verb phrase
int lineWidth = 80;
// ...
}
}
interface Repository<T, ID> { } // type parameters: short single uppercase letters
In short: UpperCamelCase for classes, interfaces, enums, records, and annotation types;
lowerCamelCase for methods, fields, local variables, and parameters; UPPER_SNAKE_CASE for
static final constants; all-lowercase reverse-domain names for packages; short uppercase letters
(T, E, K, V, R) for type parameters. Mark a field final when it never changes after
construction, and use final for genuine constants. The prevailing brace style is K&R ("Egyptian"):
the opening brace sits at the end of the line that introduces the block, and every block is braced even
when it holds a single statement.
See Also
-
Getting Started — compiling and running before you organise many files.
-
Primitive Types and Variables — the literal syntax this page only sketches.
-
Operators and Expressions — how tokens combine into expressions and statements.
-
Packages and Modules —
package,import, and the module system in depth.