Overview

LiquidJava is an additional type checker for Java. It extends Java with three main features:

  • Liquid types to restrict the values variables, parameters, and return values can have using logical predicates.
  • Typestates to describe valid object protocols across method calls.
  • Ghosts to track extra state when typestates aren’t enough.

These make it possible to catch bugs that the standard Java type system cannot, including:

  • Division by zero
  • Array index out-of-bounds
  • Values falling outside valid ranges
  • Invalid protocol usages such as reading a file after it is closed

Example

public class Example {
    public static int divide(int a, @Refinement("b != 0") int b) {
        return a / b;
    }
    public static void main(String[] args) {
        int result = divide(1, 0); // Refinement Error
    }
}

The refinement on b states that callers must provide a non-zero argument, which is checked at compile time using an SMT solver. The call divide(1, 0) violates this contract, so the verifier reports an error without the program even running.