Back to Blog
Java

Java static block: When It Runs and How to Use It

java static block: Learn how the Java static block works, when it runs, how it fits into class initialization, and common use cases with code examples.

static blockclass initializationstatic initializerJava fundamentalsclass loading
Illustration of Java class initialization with a static block executing before the main method.

The java static block is a block of code inside a class that runs once when the class is first loaded. It is used to initialize static fields or perform one-time setup before any object is created or any static method is called. Unlike instance initializer blocks, which run before each constructor call, a static block runs only once per class loader, making it a reliable place for class-level preparation.

What a Static Block Does in Java

A static block is a normal block of code enclosed in braces and prefixed with the static keyword. It appears inside a class body, typically after field declarations. The Java compiler merges all static blocks and static field initializers into a single class initializer method, which the JVM invokes when the class is initialized. This mechanism ensures that static resources are ready before the class is actively used.

Static blocks are often used to set up complex static data that cannot be expressed in a single field initializer. For example, loading a configuration file, establishing a database connection pool, or populating a static map from an external source. The block can contain any valid Java statements, including loops, conditionals, and exception handling.

Declaring a Static Block in a Class

A static block is declared directly inside the class body. Here is a minimal example:

public class Configuration { static Map<String, String> settings = new HashMap<>(); static { settings.put("url", "jdbc:mysql://localhost/db"); settings.put("timeout", "30"); System.out.println("Static block executed"); } }

The block runs when the Configuration class is first loaded, which may happen when a static member is accessed or when an instance is created. The order of execution follows the order in which static fields and static blocks appear in the source file. In the example above, the settings field is initialized first, then the static block runs and populates it.

Multiple static blocks are allowed. They are executed in the order they appear, along with static field initializers. This can be useful for separating distinct initialization concerns, but it also means the order matters. Moving a static field declaration after a static block that references it will cause a compile-time error if the field is used before declaration.

When the Static Block Runs

The JVM initializes a class just before the first active use. Active uses include creating an instance, invoking a static method, reading or writing a static field (unless it is a compile-time constant), or using reflection to access class members. When any of these happen, the JVM executes the class initializer, which contains all static field assignments and static blocks.

Consider this example:

public class Database { static { System.out.println("Database class initialized"); } static void connect() { System.out.println("Connecting..."); } } public class App { public static void main(String[] args) { Database.connect(); } }

Running App prints Database class initialized before Connecting.... The static block runs exactly once, even if connect() is called multiple times. The JVM guarantees that class initialization is thread-safe; if two threads trigger initialization simultaneously, only one thread executes the static block while the others wait.

Order of Initialization Within a Class

Within a single class, initialization follows a deterministic order: static fields and static blocks execute in textual order. Instance fields and instance initializer blocks run later, when an object is created, and in their own textual order before the constructor body. This distinction is important when a static block references static fields that are declared later.

Here is an example that demonstrates the order:

public class OrderDemo { static int a = 1; static { System.out.println("Static block 1, a=" + a); } static int b = 2; static { System.out.println("Static block 2, b=" + b); } public static void main(String[] args) { System.out.println("Main method"); } }

The output is:

Static block 1, a=1
Static block 2, b=2
Main method

If a static block tries to read a field declared after it, the field will still have its default value (zero, null, false) because it has not been initialized yet. This is a common source of subtle bugs. To avoid confusion, place static blocks after all static field declarations they depend on.

Common Use Cases for Static Blocks

Static blocks are useful when a class requires complex static initialization that cannot be done inline. A typical scenario is loading a native library:

public class NativeLib { static { System.loadLibrary("native_core"); } public native void process(); }

The library is loaded exactly once when the class is first used. Another common use is initializing a static Logger or ResourceBundle that needs configuration before first use. Static blocks also allow you to catch and handle exceptions during initialization, which is not possible with simple field initializers.

For example, a static block can read a properties file and throw an ExceptionInInitializerError if the file is missing:

public class AppConfig { static Properties props = new Properties(); static { try (InputStream in = Files.newInputStream(Paths.get("app.properties"))) { props.load(in); } catch (IOException e) { throw new ExceptionInInitializerError(e); } } }

This approach centralizes configuration loading and fails fast if the environment is misconfigured.

Static Block vs Static Method vs Instance Initializer

A static block is not a method. It cannot be called directly, has no name, and cannot return a value. It is executed automatically during class initialization. A static method, by contrast, must be explicitly invoked and can be called multiple times. If you need to perform initialization lazily or repeatedly, a static method is more appropriate.

Instance initializer blocks run before each constructor call. They are used to share initialization code across multiple constructors. The table below summarizes the key differences:

AspectStatic blockStatic methodInstance initializer
Execution triggerClass initializationExplicit callBefore each constructor call
Runs how many timesOnce per class loaderAs many times as calledOnce per object creation
Access to instance membersNoNo (unless called with an instance)Yes
Can throw checked exceptionsYes, but wrapped in ExceptionInInitializerErrorYes, must be handled or declaredYes, must be handled in constructor
Typical useOne-time setup, static resource loadingReusable logic, utility operationsCommon constructor logic

Choose a static block when the initialization must happen exactly once and cannot be deferred. Choose a static method when you need control over when the initialization runs or want to re-run it.

Handling Exceptions in a Static Block

A static block can throw checked exceptions only if they are caught inside the block. The JVM does not allow a checked exception to propagate out of the class initializer; if it does, the JVM wraps it in an ExceptionInInitializerError. This error is thrown when any thread first attempts to use the class, and it prevents the class from being used for the rest of the JVM's lifetime unless the error is caught and the class is reloaded by a different class loader.

Consider this code:

public class BrokenInit { static { int result = 1 / 0; // ArithmeticException } }

When BrokenInit is first accessed, the JVM throws ExceptionInInitializerError because the static block threw an unchecked exception. The original ArithmeticException is available as the cause. This behavior is deliberate: a class that fails to initialize is considered unusable, and subsequent attempts to use it will throw NoClassDefFoundError.

To handle initialization failures gracefully, catch the exception inside the static block and either log it or throw a custom ExceptionInInitializerError with a meaningful message. For recoverable failures, consider using lazy initialization in a static method instead, so the failure can be handled at the call site.

Static Blocks and Class Loading in Production

In production, class loading and initialization have operational implications. Static blocks run on the thread that first triggers class initialization. If that block performs slow I/O or network calls, it can block that thread and delay the application's startup. This is especially noticeable in web applications where multiple classes are initialized during the first request.

To minimize startup latency, keep static blocks lightweight. Avoid performing heavy database connections, file parsing, or network calls directly in a static block unless you have measured the impact and determined it is acceptable. If a resource is expensive to create, consider using lazy initialization with a holder class or a Supplier that defers the work until the resource is actually needed.

Another production concern is class loader isolation. In application servers, the same class may be loaded by multiple class loaders, each with its own static state. A static block runs once per class loader, so static data is not shared across different class loader scopes. This is usually the desired behavior, but it can lead to duplicated resources if the same class is deployed in multiple modules. Be aware of this when designing static caches or registries.

Finally, remember that static blocks are executed only when a class is actively used. If a class is never referenced, its static block never runs. This is useful for optional components, but it also means you cannot rely on static initialization for side effects unless you explicitly trigger class loading, for example with Class.forName("com.example.Driver").

Understanding the java static block execution model helps you write predictable initialization code and avoid the pitfalls that come with class loading order and exception handling. Use static blocks for true one-time setup, keep them fast, and always be explicit about the dependencies they require.

java static block: Practical Usage and Code Examples | RYUSLOG DEV