Jump to content

Java syntax

From Alfawiki
Java
Company typeProgramming language
IndustrySoftware development
Founded1995; 31 years ago (1995)
FounderJames Gosling, Sun Microsystems
Headquarters
Santa Clara
,
United States
Area served
Worldwide
ProductsJava Platform, Standard Edition (Java SE), Java Development Kit (JDK)
OwnerOracle Corporation
Websitewww.oracle.com/java/

The Java syntax establishes the conventions for composing and interpreting Java code.

Primarily influenced by C and C++, Java's syntax prohibits the use of global functions or variables; rather, all executable code is encapsulated within classes, with data members functioning as global variables. Except for primitive data types, which are employed to optimize performance and can be automatically converted to objects, all values are treated as objects. To streamline development and minimize errors, the language excludes features such as operator overloading and unsigned integer types.

Over time, Java's syntax has progressed through successive JDK versions, now incorporating sophisticated features like generic programming and anonymous functions (lambda expressions). Since 2017, biannual JDK releases have steadily introduced incremental improvements to the language.

Identifier

An identifier serves as a name for elements within the source code and adheres to established naming standards. Identifiers are sensitive to case and may contain:

  • Unicode letters (including numeric characters such as Roman numerals)
  • Currency symbols (for example, ¥)
  • Connecting punctuation marks (such as the underscore _)

Limitations include:

  • Identifiers cannot begin with a digit
  • They must not coincide with reserved keywords, the null literal, or Boolean literals

Keywords

The following reserved terms are prohibited from being used as identifiers:

  • _
  • abstract
  • assert
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • class
  • continue
  • default
  • do
  • double
  • else
  • enum
  • extends
  • final
  • finally
  • float
  • for
  • if
  • implements
  • import
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • super
  • switch
  • synchronized
  • this
  • throw
  • throws</text/code]
  • <text/code]transient/text/code]
  • text/code]try/text/code]
  • text/code]void/text/code]
  • text/code]volatile/text/code]
  • text/code]while/text/code]


Reserved identifiers

Certain words act as contextual keywords and are restricted only in specific situations:

  • exports
  • module
  • non-sealed</text/code]
  • text/code]open/text/code]
  • text/code]opens/text/code]
  • text/code]permits/text/code]
  • text/code]provides/text/code]
  • text/code]record/text/code]
  • text/code]requires/text/code]
  • text/code]sealed/text/code]
  • text/code]to/text/code]
  • text/code]transitive/text/code]
  • text/code]var/text/code]
  • text/code]when/text/code]
  • text/code]with/text/code]
  • text/code]yield/text/code]

Reserved keywords for literal values

These terms denote literal values recognized by the language.

  • true
  • false
  • null


Currently unused

The keywords listed below are reserved but have no active use at present.

  • const
  • goto
  • strictfp


Literal values

Integer formats
binary (added in Java SE 7) 0b11110101 (binary number preceded by the 0b prefix)
octal 0365 (octal number with a leading 0)
hexadecimal 0xF5 (hexadecimal number starting with 0x)
decimal 245 (standard decimal number)
Floating-point literals
float 23.5F, .5f, 1.72E3F (decimal fractions optionally using exponent and ending with F)
0x.5FP0F, 0x.5P-6f (hexadecimal fractions requiring an exponent and F suffix)
double 23.5D, .5, 5., 1.72E3D (decimal fractions with optional exponent and optional D suffix)
0x.5FP0, 0x.5P-6D (hexadecimal fractions with mandatory exponent and optional D)
Character literals
char 'a', 'Z', '\u0231' (single-quoted characters or escape sequences)
Boolean literals
boolean true, false
Null literal
null reference null
String literals
String "Hello, World" (text enclosed in double quotes, including escapes)
Escape sequences within strings
Unicode character \u3876 (\u followed by a hexadecimal Unicode code point up to U+FFFF)
Octal escape sequence \352 (octal number not exceeding 377, preceded by a backslash)
Line feed \n
Carriage return \r
Form feed \f
Backslash \\
Single quote \'

Integer literals default to type int, unless explicitly declared as long by appending L or l, for example, 367L. Starting with Java SE 7, underscores may be inserted between digits to improve readability; for instance, instead of .

Variables

In programming, variables serve as named references to data values. Declaring a variable involves specifying its data type and identifier, with the option to assign an initial value simultaneously.

<syntaxhighlight lang="java"> int count; // Declares variable 'count' of type int without initialization count = 35; // Assigns value to 'count' int count = 35; // Declaration combined with initialization </syntaxhighlight>

It is possible to declare and initialize multiple variables of the same type within a single statement by separating them with commas. <syntaxhighlight lang="java"> int a, b; // Declares two integer variables 'a' and 'b' int a = 2, b = 3; // Declares and initializes both variables in one line </syntaxhighlight>

Type deduction

Starting with Java 10, the compiler can automatically determine variable types through the use of var.

<syntaxhighlight lang="java"> // 'stream' type deduced as FileOutputStream from the assigned value var stream = new FileOutputStream("file.txt");

// Equivalent explicit type declaration FileOutputStream stream = new FileOutputStream("file.txt"); </syntaxhighlight>

Code scopes

Curly braces define blocks of code and establish scope boundaries, such as those enclosing class members or method implementations.

Inside methods, braces introduce nested scopes:

<syntaxhighlight lang="java"> void doSomething() {

   int a;
   {
       int b;
       a = 1;
   }
   a = 2;
   b = 3; // Invalid: 'b' is only visible within the inner block

} </syntaxhighlight>

Comments

Java provides three types of comments: block, inline, and documentation comments.

Block comments begin with /* and conclude with */, allowing multiple lines to be commented out.

<syntaxhighlight lang="java"> /* This is a multi-line comment. It can span several lines. */ </syntaxhighlight>

Inline comments start with // and continue until the end of the line.

<syntaxhighlight lang="java"> // This is an inline comment </syntaxhighlight>

Documentation comments commence with /**, adhere to Javadoc standards, and are used to generate API documentation.

<syntaxhighlight lang="java"> /**

* This is a documentation comment.
* 
* @author John Doe
*/

</syntaxhighlight>

Core types

All classes within the java.lang package are automatically imported into Java programs unless explicitly excluded. Important classes include:

java.lang.Object

java.lang.Object serves as Java’s universal superclass and top-level type. Every class without an explicit superclass inherits from it implicitly. All data types can be cast to this type, with primitive types undergoing autoboxing when converted.

java.lang.String

java.lang.String represents Java’s fundamental immutable string class. It treats each UTF-16 code unit as an individual "character," and provides methods to convert strings into an int[] array representing UTF-32 code points.

java.lang.Throwable

java.lang.Throwable is the root class for all objects that can be thrown or caught using Java’s throw and catch mechanisms.

Application architecture

Java programs consist of sets of classes organized into packages, which themselves can be nested within other classes.

The main method

Every Java program requires a designated entry point known as the main method. Although multiple classes may define a main, the primary one is specified externally (for instance, via a manifest file). The main method must be declared as public static void, accepting command-line parameters as a string array. Unlike C++ or C#, it does not return any value.

<syntaxhighlight lang=Java> public static void main(String[] args) { } </syntaxhighlight>

Packages

Packages serve to organize classes and differentiate them, while also controlling access through modifiers. For example, in java.io.InputStream, the class name is InputStream, located within the package java.io.

A package declaration appears at the beginning of a source file:

<syntaxhighlight lang=Java> package myapplication.mylibrary;

public class MyClass { } </syntaxhighlight>

Classes declared public must be saved in files named after them, with directory structures reflecting their package hierarchy (e.g., myapplication/mylibrary/MyClass.java).

Type Import Declarations

Type import declarations allow the use of type names without requiring their fully qualified names. Positioned after the package statement, these imports can be either single-type or import-on-demand.

<syntaxhighlight lang="java"> package myPackage;

import java.util.Random; // Importing a single type

public class ImportsTest {

   public static void main(String[] args) {
       Random random = new Random();
   }

} </syntaxhighlight>

Using import-on-demand imports all types from a specified package, while static imports bring in static members from classes or packages:

<syntaxhighlight lang="java"> import java.util.*; // Imports every class within java.util import java.*; // Valid syntax but ineffective; no direct classes inside java </syntaxhighlight>

Static Import Declarations

Introduced in J2SE 5.0, static import declarations permit direct access to static members of classes, interfaces, enums, or annotations without prefixing the class name:

<syntaxhighlight lang="java"> import static java.lang.System.out;

public class HelloWorld {

   public static void main(String[] args) {
       out.println("Hello World!");
   }

} </syntaxhighlight>

Import-on-demand syntax can also be applied to static members of a class:

<syntaxhighlight lang="java"> import static java.lang.System.*; </syntaxhighlight>

Static imports extend to enum constants as well. For instance, consider an enum defined in the screen package:

<syntaxhighlight lang="java"> public enum ColorName {

   RED, BLUE, GREEN

}; </syntaxhighlight>

By statically importing these constants in another class, referencing them becomes more concise:

<syntaxhighlight lang="java"> import screen.ColorName; import static screen.ColorName.*;

public class Dots {

   ColorName foo = RED;
   void shift() {
       if (foo == RED) foo = BLUE;
   }

} </syntaxhighlight>

Operators

Java's operators are similar to those found in C++, with notable exceptions: Java does not include the delete operator due to automatic memory management and absence of pointer arithmetic. Additionally, Java introduces a unique unsigned right shift operator (>>). Operator overloading is not supported in Java.

Precedence Operator Description Associativity
1 () Method call Left-to-right
[] Accessing array elements
. Selecting a member of a class
2 ++ -- Postfix increment and decrement operators
3 ++ -- Prefix increment and decrement operators Right-to-left
+ - Unary plus and minus signs
! ~ Logical NOT and bitwise complement operators
(type) val Type casting operation
new Creating new instances or arrays
4 * / % Multiplication, division, and modulus operations Left-to-right
5 + - Addition and subtraction (including string concatenation)
6 << >></ code> < code>>>></ code> Bitwise left shift, signed right shift, and unsigned right shift operators
7 < code><</ code> < code><=</ code> Less than and less than or equal relational comparisons
< code>></ code> < code>>=</ code> Greater than and greater than or equal relational comparisons
< code>instanceof</ code> Type checking operator
8 < code>==</ code> < code>!=</ code> Equality and inequality comparisons
9 < code>&</ code> Bitwise AND and logical AND operations
10 < code>^</ code> Bitwise XOR and logical exclusive OR operations
11 | Bitwise OR and logical inclusive OR operations
12 < code>&&</ code> Logical AND conditional operator
13 || Logical OR conditional operator
14 < code>c ? t : f</ code> Ternary conditional expression Right-to-left
15 < code>=</ code> Simple assignment operator
= </ code> Compound assignments involving arithmetic, bitwise, and shift operations


if Statement

Java's if statements are syntactically similar to those found in C, following the same structure: <syntaxhighlight lang="java"> if (i == 3) {

   doSomething();

} </syntaxhighlight>

An optional else clause allows the formation of an if-then-else construct: <syntaxhighlight lang="java"> if (i == 3) {

   doSomething();

} else {

   doSomethingElse();

} </syntaxhighlight>

The else-if pattern is implemented as a chain of if-then-else blocks without any dedicated keyword: <syntaxhighlight lang="java"> if (i == 3) {

   doSomething();

} else if (i == 2) {

   doSomethingElse();

} else {

   doSomethingDifferent();

} </syntaxhighlight>

For simpler conditional assignments, the ?: operator provides a compact alternative: <syntaxhighlight lang="java"> int a = 1; int b = 2; int minVal = (a < b) ? a : b; </syntaxhighlight>

switch Statement

In Java, the switch statement accepts variables of types byte, short, char, int, their corresponding wrapper classes, and since J2SE 5.0, enum types. Starting from Java SE 7, it also supports String objects. Other reference types are not permitted.

Each case label must be a constant value, including enum constants and string literals. Execution begins at the matching case label, with an optional default case to handle unmatched values. Typically, each case concludes with a break statement to avoid fall-through behavior; omitting it may lead to compiler warnings.

<syntaxhighlight lang="java"> switch (ch) {

   case 'A':
       doSomething();
       break;
   case 'B':
   case 'C':
       doSomethingElse();
       break;
   default:
       doSomethingDifferent();
       break;

} </syntaxhighlight>

switch Expressions

Starting with Java 14, switch expressions introduce arrow syntax to enable clearer and expression-oriented control flow:

<syntaxhighlight lang="java"> var result = switch (ch) {

   case 'A' -> Result.GREAT;
   case 'B', 'C' -> Result.FINE;
   default -> throw new ThisIsNoGoodException();

}; </syntaxhighlight>

Alternatively, the yield keyword can be employed within switch expressions; however, arrow syntax is generally favored to prevent unintended fall-through:

<syntaxhighlight lang="java"> var result = switch (ch) {

   case 'A':
       yield Result.GREAT;
   case 'B':
   case 'C':
       yield Result.FINE;
   default:
       throw new ThisIsNoGoodException();

}; </syntaxhighlight>

Iteration Statements

Iteration statements enable repetitive execution of code blocks as long as a specified condition evaluates to true. Since J2SE 5.0, Java has supported four distinct looping constructs. The controlling condition must be a boolean or Boolean type; unlike C, non-boolean expressions such as <syntaxhighlight lang="c"> while (1) {

   doSomething();

} </syntaxhighlight> will not compile.

while Loop

A while loop evaluates its condition before each iteration:

<syntaxhighlight lang="java"> while (i < 10) {

   doSomething();

} </syntaxhighlight>

do ... while Loop

In a do ... while loop, the condition is evaluated after each cycle, guaranteeing that the loop body executes at least once:

<syntaxhighlight lang="java"> // doSomething() executes at least once do {

   doSomething();

} while (i < 10); </syntaxhighlight>

for loop

Java's for loops consist of three parts: an initializer, a condition, and an update expression. You can separate multiple initializers or update expressions with commas (but not conditions). Unlike C, commas serve as separators rather than operators:

<syntaxhighlight lang="java"> for (int i = 0; i < 10; i++) {

   doSomething();

}

// Loop using two variables for (int i = 0, j = 9; i < 10; i++, j -= 3) {

   doSomething();

} </syntaxhighlight>

Each of these three components is optional; for instance, omitting all results in an endless loop:

<syntaxhighlight lang="java"> for (;;) {

   doSomething();

} </syntaxhighlight>

Enhanced for loop

Introduced in J2SE 5.0, the enhanced for loop simplifies iterating over arrays and collections by internally using iterators to return elements one by one. Unlike C#, which employs a specific keyword, Java uses a unique syntax:

<syntaxhighlight lang="java"> for (int i : intArray) {

   doSomething(i);

} </syntaxhighlight>

Labels

Labels identify specific locations in code that can be targeted by break and continue. Although Java reserves the goto keyword, it cannot be used.

<syntaxhighlight lang="java"> start: someMethod(); </syntaxhighlight>

break statement

The break statement terminates the closest enclosing loop or switch, transferring control to the statement following it:

<syntaxhighlight lang="java"> for (int i = 0; i < 10; i++) {

   while (true) {
       break;
   }
   // Execution continues here

} </syntaxhighlight>

By employing labels, it's possible to break out of outer loops:

<syntaxhighlight lang="java"> outer: for (int i = 0; i < 10; i++) {

   while (true) {
       break outer;
   }

} // Execution resumes here </syntaxhighlight>

continue statement

The continue statement skips the current iteration within a loop and advances to the next cycle. In this example, a while loop reads characters via getChar(), bypassing subsequent statements if the character is a space:

<syntaxhighlight lang="java"> int ch; while ((ch = getChar()) != -1) {

   if (ch == ' ') {
       continue; // Skips remaining code in this iteration
   }
   doSomething();

} </syntaxhighlight>

Labels can also be combined with continue and break to manage outer loops more precisely:

<syntaxhighlight lang="java"> outer: for (String str : stringsArr) {

   char[] strChars = str.toCharArray();
   for (char ch : strChars) {
       if (ch == ' ') {
           continue outer; // Proceeds to next string in stringsArr
       }
       doSomething(ch);
   }

} </syntaxhighlight>

return statement

The return statement ends method execution and may optionally provide a return value. Methods with a non-void return type must include a return. Examples include:

<syntaxhighlight lang="java"> void doSomething(boolean streamClosed) {

   if (streamClosed) {
       return;
   }
   readFromStream();

}

int calculateSum(int a, int b) {

   return a + b;

} </syntaxhighlight>

A return causes immediate termination of method execution unless it occurs inside a try block with an associated finally, in which case control passes to the finally block before exiting:

<syntaxhighlight lang="java"> void doSomething(boolean streamClosed) {

   try {
       if (streamClosed) {
           return;
       }
       readFromStream();
   } finally {
       freeResources();
   }

} </syntaxhighlight>

try-catch-finally Blocks

Exception management in Java utilizes try, catch, and optionally finally blocks to handle runtime anomalies:

<syntaxhighlight lang="java"> try {

   methodThrowingExceptions();

} catch (Exception ex) {

   reportException(ex);

} finally {

   freeResources();

} </syntaxhighlight>

When an exception is thrown inside the try block, control transfers to the first catch clause that matches the exception type. Starting with Java 7, multiple exceptions can be caught in a single catch block using the multi-catch feature:

<syntaxhighlight lang="java"> try {

   methodThrowingExceptions();

} catch (IOException | IllegalArgumentException ex) {

   reportException(ex);

} </syntaxhighlight>

If no suitable catch block exists, the exception propagates up the call stack until it is handled or causes program termination. The finally block executes unconditionally after the try/catch, ensuring cleanup actions run regardless of exceptions or early returns.

A try block must be followed by at least one catch or a finally block.

try-with-resources Statements

Introduced in Java SE 7, try-with-resources statements simplify resource management by automatically closing resources once the try block finishes. Resources used must implement the java.lang.AutoCloseable interface. Unlike traditional try-catch-finally, these statements do not mandate explicit catch or finally clauses for resource cleanup.

<syntaxhighlight lang="java"> try (FileOutputStream fos = new FileOutputStream("filename");

   XMLEncoder xEnc = new XMLEncoder(fos)) {
   xEnc.writeObject(object);

} catch (IOException ex) {

   Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);

} </syntaxhighlight>

From Java 9 onward, previously declared variables can be included directly in the resource specification:

<syntaxhighlight lang="java"> FileOutputStream fos = new FileOutputStream("filename"); XMLEncoder xEnc = new XMLEncoder(fos); try (fos; xEnc) {

   xEnc.writeObject(object);

} catch (IOException ex) {

   Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);

} </syntaxhighlight>

throw Statement

The throw keyword explicitly triggers an exception, terminating the current method or block execution. The exception object follows immediately after the keyword.

<syntaxhighlight lang="java"> void methodThrowingExceptions(Object obj) {

   if (obj == null) {
       throw new NullPointerException();
   }
   doSomethingWithObject(obj);

} </syntaxhighlight>

Thread Synchronization

Java facilitates concurrent programming through built-in synchronization mechanisms. The synchronized construct enforces mutual exclusion by locking on a non-null reference object before executing a critical section. This lock prevents simultaneous access by other threads until it is released.

<syntaxhighlight lang="java"> synchronized (someObject) {

   // Synchronized statements

} </syntaxhighlight>

assert statement

Introduced in J2SE 1.4, the assert statement provides a mechanism for runtime assertions that can be toggled on or off at the class or package level. It triggers an exception if the evaluated condition is false, with the option to include a descriptive message.

<syntaxhighlight lang="java"> // Throws AssertionError if n is zero assert n != 0; /* Throws AssertionError with message if n is zero */ assert n != 0 : "n was equal to zero"; </syntaxhighlight>

Primitive types

Java's primitive data types encompass integer values, floating-point numbers, UTF-16 code units, and a Boolean type. Aside from the char type, which represents UTF-16 code units, Java does not provide unsigned types. This is partially mitigated by the presence of the unsigned right shift operator (>>), which is not found in C++. However, this distinction has been criticized for limiting interoperability with C and C++.

Primitive Types
Type Wrapper class Category Range Size Default Value
byte java.lang.Byte integer −128 to 127 8-bit (1 byte) 0
short java.lang.Short integer −32,768 to 32,767 16-bit (2 bytes) 0
int java.lang.Integer integer −2,147,483,648 to 2,147,483,647 32-bit (4 bytes) 0
long java.lang.Long integer −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 64-bit (8 bytes) 0
float java.lang.Float floating-point number ±1.401298E−45 to ±3.402823E+38 32-bit (4 bytes) 0.0f
double java.lang.Double floating-point number ±4.94065645841246E−324 to ±1.79769313486232E+308 64-bit (8 bytes) 0.0
boolean java.lang.Boolean Boolean true or false 1-bit (1 bit) false
char java.lang.Character UTF-16 code unit (either a BMP character or part of a surrogate pair) '\u0000' to '\uFFFF' 16-bit (2 bytes) '\u0000'

The char type can represent either a single character or one half of a surrogate pair used for encoding Unicode code points outside the Basic Multilingual Plane.

Boxing and unboxing

Since J2SE 5.0, boxing refers to the automatic conversion of primitive values into their corresponding wrapper class objects; unboxing denotes the reverse process. These conversions happen implicitly without requiring explicit casting.

Example: <syntaxhighlight lang="java"> int foo = 42; // primitive int value Integer bar = foo; // automatic boxing to Integer object int foo2 = bar; // automatic unboxing back to primitive int </syntaxhighlight>

Reference types

Reference types consist of classes, interfaces, and arrays. Invoking a constructor results in an object being allocated on the heap with a reference assigned to a variable. Once that variable goes out of scope and no references remain pointing to the object, it becomes eligible for garbage collection.

A reference variable holds the value null when it does not refer to any object instance.

Arrays

In Java, arrays are instantiated during program execution similarly to objects. Once created, their size remains constant.

<syntaxhighlight lang="java"> int[] numbers = new int[5]; numbers[0] = 2; numbers[1] = 5; int x = numbers[0]; </syntaxhighlight>

Initializers

<syntaxhighlight lang="java"> // Verbose form int[] numbers = new int[] {20, 1, 42, 15, 34}; // Concise form int[] numbers2 = {20, 1, 42, 15, 34}; </syntaxhighlight>

Multi-dimensional arrays

Multi-dimensional arrays consist of arrays containing other arrays, represented as references to subordinate arrays.

<syntaxhighlight lang="java"> int[][] numbers = new int[3][3]; numbers[1][2] = 2;

int[][] numbers2 = {{2, 3, 2}, {1, 2, 6}, {2, 4, 5}}; </syntaxhighlight>

Since sub-arrays may have different lengths, multi-dimensional arrays do not have to be uniform rectangles:

<syntaxhighlight lang=java> int[][] numbers = new int[2][]; // Only the first dimension is allocated

numbers[0] = new int[3]; numbers[1] = new int[2]; </syntaxhighlight>

Classes

Classes form the foundation of Java’s object-oriented paradigm. They encapsulate members that hold and manage data. Classes are divided into top-level and nested categories. Nested classes are defined within another class and can access its private fields. These include member classes (which can be static or inner), local classes, and anonymous classes.

Declaration

Top-level class <syntaxhighlight lang="java">

class Foo {

   // Class members

} </syntaxhighlight>

Inner class <syntaxhighlight lang="java">

class Foo { // Top-level class

   class Bar { // Inner class
   }

} </syntaxhighlight>

Nested class <syntaxhighlight lang="java">

class Foo { // Top-level class

   static class Bar { // Nested class
   }

} </syntaxhighlight>

Local class <syntaxhighlight lang="java">

class Foo {

   void bar() {
       class Foobar {// Local class inside a method
       }
   }

} </syntaxhighlight>

Anonymous class <syntaxhighlight lang="java">

class Foo {

   void bar() {
       new Object() {// Anonymous subclass of Object
       };
   }

} </syntaxhighlight>

Instantiation

Instance variables and methods tied to specific objects are defined as non-static members. Objects are created by applying the new keyword along with the constructor.

<syntaxhighlight lang="java"> Foo foo = new Foo(); </syntaxhighlight>

Accessing members

Both instance and static members are accessed using the . (dot) operator.

Accessing instance members
Instance fields and methods are referenced through an object variable.

<syntaxhighlight lang="java"> String foo = "Hello"; String bar = foo.toUpperCase(); </syntaxhighlight>

Accessing static members
Static members declared with the static keyword belong to the class itself and are accessed via the class name without needing an object instance.

<syntaxhighlight lang="java"> public class Foo {

   public static void doSomething() {
   }

}

// Invoking the static method Foo.doSomething(); </syntaxhighlight>

Modifiers

Modifiers serve to adjust declarations of types and their members, prominently including those that govern access levels.

  • abstract - Specifies a base class that cannot be directly instantiated.
  • static - When applied to member classes, indicates the class is not tied to any instance.
  • final - Prevents further subclassing of a class.
  • strictfp - Guarantees floating-point calculations adhere strictly to IEEE 754 standards.
Access modifiers

Access modifiers regulate the visibility scope of classes and their members. Members declared as public are accessible from any location, whereas omission of an access modifier results in default (package-private) visibility.

<syntaxhighlight lang="java"> public class Foo {

   int go() {
       return 0;
   }
   private class Bar {
   }

} </syntaxhighlight>

The following table outlines accessibility based on modifier and context:

Modifier Same or nested class Other class in package Subclass in another package Non-subclass in another package
private yes no no no
default (package private) yes yes no no
protected yes yes yes no
public yes yes yes yes


Constructors and initializers

A constructor is responsible for setting up object fields when a new instance is created. Unlike methods, constructors do not specify a return type and bear the same name as their class:

<syntaxhighlight lang="java"> class Foo {

   String str;
   Foo() { // No-argument constructor
       // Initialization logic here
   }
   Foo(String str) { // Constructor accepting a parameter
       this.str = str;
   }

} </syntaxhighlight>

Initializers execute code blocks during either class loading or object instantiation.

Static initializers, marked with static, are executed once when the class is loaded into memory:

<syntaxhighlight lang="java"> class Foo {

   static {
       // Static initialization code
   }

} </syntaxhighlight>

Instance initializers run before every constructor invocation and do not accept parameters or throw checked exceptions:

<syntaxhighlight lang="java"> class Foo {

   {
       // Instance initialization code
   }

} </syntaxhighlight>

Java manages memory through garbage collection rather than destructors. Objects may override the finalize() method, which is invoked prior to garbage collection, to perform necessary cleanup.

Methods

In Java, all executable statements must reside within methods, which are associated with classes and characterized by a return type, method name, and parameters. Methods that do not return values declare the void return type. Unlike C++, Java does not support default argument values in methods; instead, method overloading is commonly used.

<syntaxhighlight lang="java"> class Foo {

   int bar(int a, int b) {
       return (a*2) + b;
   }
   /* Overloaded version with different parameter list */
   int bar(int a) {
       return a*2;
   }

} </syntaxhighlight>

Methods are invoked using the . operator on an object instance or, for static methods, on the class itself.

<syntaxhighlight lang="java"> Foo foo = new Foo(); int result = foo.bar(7, 2); // Invocation of non-static method

int finalResult = Math.abs(result); // Invocation of static method </syntaxhighlight>

The throws clause declares exceptions that a method might propagate. All checked exceptions must be listed as a comma-separated sequence.

<syntaxhighlight lang="java"> void openStream() throws IOException, myException { } </syntaxhighlight>

Modifiers
  • abstract - Specifies methods without implementations within abstract classes; such methods must be implemented in subclasses unless those subclasses are also abstract.
  • static - Enables method invocation without needing an instance; cannot interact with non-static members.
  • final - Disallows method overriding in any subclass.
  • native - Marks methods as implemented outside of Java, typically through JNI, for platform-specific functionality.
  • strictfp - Guarantees adherence to IEEE 754 standards for floating-point calculations.
  • synchronized - Requires a thread to obtain a monitor lock before execution; the monitor corresponds to the instance or java.lang.Class for static methods.
  • Access modifiers used here correspond to those applied to classes.
Varargs

Introduced in J2SE 5.0, varargs methods accept a flexible number of arguments of a specified type, treated as an array within the method.

<syntaxhighlight lang="java"> void printReport(String header, int... numbers) {

   System.out.println(header);
   for (int num : numbers) {
       System.out.println(num);
   }

}

// Example invocation of varargs method printReport("Report data", 74, 83, 25, 96); </syntaxhighlight>

Fields

Fields, also known as class variables, are declared inside the class body and hold data values.

<syntaxhighlight lang="java"> class Foo {

   double bar;

} </syntaxhighlight>

It is also possible to assign initial values to fields at the point of declaration.

<syntaxhighlight lang="java"> class Foo {

   double bar = 2.3;

} </syntaxhighlight>

Modifiers
  • static - Defines the field as belonging to the class rather than instances.
  • final - Permits assignment only once, either during declaration, within constructors, or initialization blocks.
  • transient - Prevents the field from being serialized during object serialization.
  • volatile - Guarantees visibility of changes to the field across multiple threads.

Inheritance

Java supports single inheritance where a class extends only one superclass using extends. Classes declared as final cannot serve as superclasses. The keyword this points to the current object, while super accesses members of the immediate superclass.

<syntaxhighlight lang="java"> class Foo {}

class Foobar extends Foo {} </syntaxhighlight>

When no superclass is explicitly declared, a class implicitly inherits from java.lang.Object. If the superclass lacks a no-argument constructor, subclasses must explicitly invoke one of its constructors:

<syntaxhighlight lang="java"> class Foo {

   public Foo(int n) { }

}

class Foobar extends Foo {

   private int number;
   public Foobar(int number) {
       super(number);
       this.number = number;
   }

} </syntaxhighlight>

Overriding methods

In Java, all methods except those marked final are virtual by default and may be overridden in derived classes.

<syntaxhighlight lang="java"> class Operation {

   public int doSomething() { return 0; }

}

class NewOperation extends Operation {

   @Override
   public int doSomething() { return 1; }

} </syntaxhighlight>

Abstract classes

An Abstract Class is a class that is not fully defined and thus cannot be instantiated on its own.

A class qualifies as abstract if it:

  • Contains abstract methods,
  • Inherits abstract methods that remain unimplemented,
  • Or implements interfaces with abstract methods that have not been overridden.

Instances of subclasses derived from abstract classes can be created, which will invoke the constructors and initialize the fields of the abstract superclass.

<syntaxhighlight lang="java"> package org.dwwwp.test;

public class AbstractClass {

   private static final String hello;
   static {
       System.out.println(AbstractClass.class.getName() + ": static block runtime");
       hello = "hello from " + AbstractClass.class.getName();
   }
   {
       System.out.println(AbstractClass.class.getName() + ": instance block runtime");
   }
   public AbstractClass() {
       System.out.println(AbstractClass.class.getName() + ": constructor runtime");
   }
   public static void hello() {
       System.out.println(hello);
   }

} </syntaxhighlight> <syntaxhighlight lang="java"> package org.dwwwp.test;

public class CustomClass extends AbstractClass {

   static {
       System.out.println(CustomClass.class.getName() + ": static block runtime");
   }
   {
       System.out.println(CustomClass.class.getName() + ": instance block runtime");
   }
   public CustomClass() {
       System.out.println(CustomClass.class.getName() + ": constructor runtime");
   }
   public static void main(String[] args) {
       CustomClass nc = new CustomClass();
       hello();
   }

} </syntaxhighlight>

Output: <syntaxhighlight lang="text"> org.dwwwp.test.AbstractClass: static block runtime org.dwwwp.test.CustomClass: static block runtime org.dwwwp.test.AbstractClass: instance block runtime org.dwwwp.test.AbstractClass: constructor runtime org.dwwwp.test.CustomClass: instance block runtime org.dwwwp.test.CustomClass: constructor runtime hello from org.dwwwp.test.AbstractClass </syntaxhighlight>

Enumerations

Enumerations, introduced with J2SE 5.0, are specialized classes that encapsulate a fixed set of enum constants, each representing an instance of the enumeration type. These enum classes cannot be instantiated externally beyond their defined scope.

<syntaxhighlight lang="java"> enum Season {

   WINTER, SPRING, SUMMER, AUTUMN

} </syntaxhighlight>

When the class is loaded, constructors associated with enum constants may be executed:

<syntaxhighlight lang="java"> public enum Season {

   WINTER("Cold"), SPRING("Warmer"), SUMMER("Hot"), AUTUMN("Cooler");
   private final String description;
   Season(String description) {
       this.description = description;
   }
   public String getDescription() {
       return description;
   }

} </syntaxhighlight>

Enum classes can also include bodies for each constant, functioning as anonymous subclasses extending the enum:

<syntaxhighlight lang="java"> public enum Season {

   WINTER {
       String getDescription() { return "cold"; }
   },
   SPRING {
       String getDescription() { return "warmer"; }
   },
   SUMMER {
       String getDescription() { return "hot"; }
   },
   FALL {
       String getDescription() { return "cooler"; }
   };

} </syntaxhighlight>

Interfaces

Interfaces specify method signatures without providing implementations and do not contain any fields. By definition, every interface is abstract. Starting with Java SE 8, interfaces can include static and default method implementations, offering greater adaptability for enterprise software development.

<syntaxhighlight lang="java"> interface ActionListener {

   int ACTION_ADD = 0;
   int ACTION_REMOVE = 1;
   void actionSelected(int action);

} </syntaxhighlight>

Implementing an interface

To implement an interface, a class uses the implements keyword and may implement several interfaces separated by commas. All interface methods must be provided with concrete implementations unless the class itself is declared abstract.

<syntaxhighlight lang="java"> interface RequestListener {

   int requestReceived();

}

class ActionHandler implements ActionListener, RequestListener {

   public void actionSelected(int action) { }
   public int requestReceived() { return 0; }

}

// Using interface reference RequestListener listener = new ActionHandler(); listener.requestReceived(); </syntaxhighlight>

Functional interfaces and lambda expressions

With Java SE 8, functional interfaces—those containing exactly one abstract method—were introduced, facilitating succinct coding through lambda expressions. This advancement promotes streamlined development and supports functional programming techniques beneficial in business software solutions. Applying the optional @FunctionalInterface annotation ensures compile-time verification of the interface's functional nature.

<syntaxhighlight lang="java"> // Functional interface @FunctionalInterface interface Calculation {

   int calculate(int a, int b);

}

// Method receiving functional interface int runCalculation(Calculation calculation) {

   return calculation.calculate(1, 2);

}

// Lambda expression example runCalculation((a, b) -> a + b);

// Equivalent anonymous class implementation runCalculation(new Calculation() {

   @Override
   public int calculate(int a, int b) {
       return a + b;
   }

}); </syntaxhighlight>

Lambda expressions benefit from type inference and concise syntax; parentheses can be omitted when there is only one parameter.

<syntaxhighlight lang="java"> // Lambda with explicit parameter types and block body runCalculation((int a, int b) -> { return a + b; });

// Functional interface with single parameter interface StringExtender {

   String extendString(String input);

}

// Lambda assignment StringExtender extender = input -> input + " Extended"; </syntaxhighlight>

Method references

When an existing method matches the signature of a functional interface's abstract method, it can replace a lambda expression using a method reference. These references fall into several categories:

Type of reference Example Corresponding lambda expression
Static method Integer::sum (a, b) -> a + b
Bound instance method "LongString"::substring i -> "LongString".substring(i)
Unbound instance method String::isEmpty s -> s.isEmpty()
Class constructor ArrayList<String>::new capacity -> new ArrayList<String>(capacity)
Array constructor String[]::new size -> new String[size]

For instance, invoking runCalculation can be simplified as:

<syntaxhighlight lang="java"> runCalculation(Integer::sum); </syntaxhighlight>

Inheritance

Unlike classes, interfaces are capable of inheriting from multiple other interfaces simultaneously. However, if two or more inherited interfaces declare members with identical names, those members become ambiguous and cannot be accessed.

<syntaxhighlight lang="java"> interface EventListener extends ActionListener, RequestListener { } </syntaxhighlight>

Default methods

With the arrival of Java SE 8, default methods were introduced to allow new methods within interfaces without disrupting existing implementations. These methods provide a body and are executed unless explicitly overridden by implementing classes.

<syntaxhighlight lang="java"> interface StringManipulator {

   String extendString(String input);
   
   default String shortenString(String input) {
       return input.substring(1);
   }

}

class PartialStringManipulator implements StringManipulator {

   @Override
   public String extendString(String input) {
       return input + " Extended";
   }

} </syntaxhighlight>

Static methods

Java SE 8 also brought static methods into interfaces, functioning similarly to static methods in classes.

<syntaxhighlight lang="java"> interface StringUtils {

   static String shortenByOneSymbol(String input) {
       return input.substring(1);
   }

}

StringUtils.shortenByOneSymbol("Test"); </syntaxhighlight>

Private methods

Java 9 introduced private methods within interfaces to facilitate code reuse among default methods while keeping these helper methods hidden from the implementing classes.

<syntaxhighlight lang="java"> interface Logger {

   default void logError() {
       log(Level.ERROR);
   }
   default void logInfo() {
       log(Level.INFO);
   }
   private void log(Level level) {
       SystemLogger.log(level.id);
   }

} </syntaxhighlight>

Annotations

Annotations in Java serve as embedded metadata within source code and were first introduced in J2SE 5.0.

Annotation types

Java provides built-in annotation types and supports defining custom annotations. Declaring an annotation type resembles creating an interface but uses the @ symbol preceding interface. All annotation types implicitly implement java.lang.annotation.Annotation and cannot extend other interfaces or classes.

<syntaxhighlight lang="java"> @interface BlockingOperations { } </syntaxhighlight>

Annotations may declare parameterless methods that do not throw exceptions and can include enums or other annotations. Methods may specify default values using the default keyword:

<syntaxhighlight lang="java"> @interface BlockingOperations {

   boolean fileSystemOperations();
   boolean networkOperations() default false;

} </syntaxhighlight>

Usage of annotations

Annotations can be applied to various program elements such as packages, classes (including enums), interfaces (including other annotations), fields, methods, parameters, constructors, local variables, and enum constants. They are denoted by @ followed by the annotation name and optional element-value pairs enclosed in parentheses. Elements without predefined defaults must be explicitly assigned values.

<syntaxhighlight lang="java"> @BlockingOperations(/*mandatory*/ fileSystemOperations, /*optional*/ networkOperations = true) void openOutputStream() { //Annotated method } </syntaxhighlight>

There are two concise annotation forms: marker annotations, which omit element assignments entirely, and single-element annotations, used when only one element lacks a default value. In the latter case, the element name can be omitted:

<syntaxhighlight lang="java"> @Unused // Equivalent to @Unused() void travelToJupiter() { } </syntaxhighlight>

<syntaxhighlight lang="java"> /* Equivalent to @BlockingOperations(fileSystemOperations = true). networkOperations uses its default */

@BlockingOperations(true) void openOutputStream() { } </syntaxhighlight>

Generics

Generics, introduced with J2SE 5.0, provide parameterized types that allow code to work with different data types safely without requiring explicit type declarations. They enhance type safety by identifying type-related errors during compilation. In contrast to C#, Java implements generics through type erasure, which means that type parameter information is not retained at runtime.

Generic classes

Type parameters can be added to classes by including type variables within angle brackets (< and >) immediately following the class name. These variables can then be utilized throughout the class members in place of specific types. It is possible to declare multiple type parameters separated by commas.

Type parameters may be limited to subclasses of a particular class or interfaces by using the extends keyword. When bounding a type variable by both a class and interfaces, the class must be listed first, followed by interface names separated with &.

<syntaxhighlight lang="java"> /* Class with two type parameters: T must extend ArrayList and implement Formattable */ public class Mapper<T extends ArrayList & Formattable, V> {

   public void add(T array, V item) {
       array.add(item);
   }

} </syntaxhighlight>

When specifying or instantiating parameterized types, actual types replace the type variables using the same syntax as in the class declaration.

<syntaxhighlight lang="java"> /* Mapper instantiated with CustomList as T and Integer as V. CustomList must extend ArrayList and implement Formattable */ Mapper<CustomList, Integer> mapper = new Mapper<CustomList, Integer>(); </syntaxhighlight>

Starting from Java SE 7, the diamond operator (<>) enables type inference, which simplifies object creation:

<syntaxhighlight lang="java"> Mapper<CustomList, Integer> mapper = new Mapper<>(); </syntaxhighlight>

Wildcards (?) may substitute explicit type parameters when declaring generic variables. These wildcards can be bounded by specifying upper bounds with extends or lower bounds with super.

<syntaxhighlight lang="java"> /* Accepts any Mapper instance with CustomList as the first parameter, regardless of the second parameter's type */ Mapper<CustomList, ?> mapper; mapper = new Mapper<CustomList, Boolean>(); mapper = new Mapper<CustomList, Integer>();

/* Accepts only Mappers where the second parameter extends Number */ void addMapper(Mapper<?, ? extends Number> mapper) { } </syntaxhighlight>

Generic methods and constructors

Generics can also be applied to individual methods or constructors. The type parameters are declared before the method’s return type or before the constructor name.

<syntaxhighlight lang="java"> class Mapper {

   // Generic constructor in a non-generic class
   <T, V> Mapper(T array, V item) {
   }

}

/* Method that accepts arrays containing elements of the same type as the searched item or its subclasses */ static <T, V extends T> boolean contains(T item, V[] arr) {

   for (T currentItem : arr) {
       if (item.equals(currentItem)) {
           return true;
       }
   }
   return false;

} </syntaxhighlight>

Generic Interfaces

Just like classes, interfaces can also be defined with type parameters.

<syntaxhighlight lang="java"> interface Expandable<T extends Number> {

   void addItem(T item);

}

// Class with type parameter class Array<T extends Number> implements Expandable<T> {

   void addItem(T item) {
   }

}

// Class without type parameter, specifying type explicitly class IntegerArray implements Expandable<Integer> {

   void addItem(Integer item) {
   }

} </syntaxhighlight>

See also

References


External links