Law of Demeter in Java Explained with Examples

Introduction

This tutorial explains the Law of Demeter, also called the principle of least knowledge, with Java examples. We will start with what the law says and which objects a method is allowed to talk to. We will then see a Java example that breaks it with a chain of getters, and watch that chain send a leave request to the wrong person after a small change elsewhere in the code. Next, we will fix it, and look at the cases where long chains of calls are perfectly fine. Lastly, we will cover the common objections and how the law relates to other principles.

What is the Law of Demeter

The Law of Demeter was proposed in 1987 by Ian Holland and colleagues at Northeastern University, while working on a project named Demeter. It limits which objects a method may call methods on. A method m() of an object O should only invoke methods of -
  • O itself (its own methods),
  • the objects held in O's fields,
  • the parameters passed to m(),
  • the objects that m() creates.
These are the method's friends. An object returned by a friend's method is a stranger, and the method should not call methods on it. The short form is "only talk to your immediate friends", or, more loosely, "use only one dot".
Law of Demeter - a method may talk to its friends (this, fields, parameters, created objects) but not to strangers returned by them

Why it matters

A chain such as employee.getDepartment().getManager().email() means that the calling code knows three things: that an employee has a department, that a department has a manager, and that a manager has an email address. If any of these relationships changes, every chain that walks through it must change too. The caller is coupledClick to read tutorial: Coupling and Cohesion Explained with Java Examples to the whole object structure, not just to the object it was given. Such chains are nicknamed train wrecks.

Example - a train wreck that goes wrong

Leave requests must go to the employee's approver. Two services do the same job below: ChainedLeaveService walks the object graph itself, and LeaveService asks the employee. Then a new rule is added inside Department: while a manager is on leave, the deputy approves requests.
Java code showing a Law of Demeter violation and its fix
//DemeterExample.java
public class DemeterExample {

  record Manager(String name, String email) {}

  static class Department {
    private final Manager manager;
    private final Manager deputy;
    private boolean managerOnLeave = false;

    Department(Manager manager, Manager deputy) {
      this.manager = manager;
      this.deputy = deputy;
    }

    Manager getManager() { return manager; }
    void setManagerOnLeave(boolean onLeave) { this.managerOnLeave = onLeave; }

    // The department knows its own approval rule
    String approverEmail() {
      return managerOnLeave ? deputy.email() : manager.email();
    }
  }

  static class Employee {
    private final String name;
    private final Department department;

    Employee(String name, Department department) {
      this.name = name;
      this.department = department;
    }

    String getName() { return name; }
    Department getDepartment() { return department; }

    // Delegates the question to its own friend
    String approverEmail() { return department.approverEmail(); }
  }

  // Violates the Law of Demeter: walks through Department to Manager
  static class ChainedLeaveService {
    String request(Employee e, int days) {
      String to = e.getDepartment().getManager().email();
      return e.getName() + ", " + days + " days -> " + to;
    }
  }

  // Follows the Law of Demeter: talks only to its parameter
  static class LeaveService {
    String request(Employee e, int days) {
      return e.getName() + ", " + days + " days -> " + e.approverEmail();
    }
  }

  public static void main(String[] args) {
    Department finance = new Department(
        new Manager("Deborah Sprightly", "deborah@example.com"),
        new Manager("Ethan Hardy", "ethan@example.com"));
    Employee tom = new Employee("Tom Jones", finance);

    System.out.println("Chained : " + new ChainedLeaveService().request(tom, 3));
    System.out.println("Demeter : " + new LeaveService().request(tom, 3));

    finance.setManagerOnLeave(true);
    System.out.println("-- Deborah is on leave; Ethan approves --");
    System.out.println("Chained : " + new ChainedLeaveService().request(tom, 3));
    System.out.println("Demeter : " + new LeaveService().request(tom, 3));
  }
}
 OUTPUT of the above code
Chained : Tom Jones, 3 days -> deborah@example.com
Demeter : Tom Jones, 3 days -> deborah@example.com
-- Deborah is on leave; Ethan approves --
Chained : Tom Jones, 3 days -> deborah@example.com
Demeter : Tom Jones, 3 days -> ethan@example.com

Explanation of the code

  • ChainedLeaveService.request() calls getDepartment() on its parameter (allowed), then getManager() on the returned Department and email() on the returned Manager (both strangers). It has copied the rule "the manager approves" into its own code.
  • LeaveService.request() calls one method on its parameter. Who approves is decided by Employee and Department, which own the data.
  • When the deputy rule was added to Department.approverEmail(), LeaveService picked it up without any change. ChainedLeaveService kept sending requests to the manager who is on leave - it compiled, ran, and was wrong.
  • In a real codebase there would be many chained callers: the leave screen, the expense approval, the overtime report. Each would need to be found and fixed. With approverEmail(), the rule changes in one place.

How to fix a Law of Demeter violation

  • Ask for what you need, not for the path to it: add a method to the friend that answers the actual question, as approverEmail() does. The chain moves inside the objects, where each step only talks to its own field.
  • Tell the object to do the work: often the caller only fetched the stranger to act on it. Moving the action into the object is the Tell, Don't AskClick to read tutorial: Tell, Don't Ask Principle Explained with Java Examples principle.
  • Pass the right object in: if a method only needs the manager, take a Manager parameter instead of an Employee it has to dig through.

When chained calls are fine

The Law of Demeter is about objects that hide structure. Counting dots is only a rough guide, and many long chains do not break the law at all -
  • Fluent APIs and builders: each call returns the same object, or a new object of the same kind, so the caller never meets a stranger. new StringBuilder().append(a).append(b).toString() talks to one builder.
  • Streams: list.stream().filter(...).map(...).toList() is a pipeline of operations on one stream abstraction; see the Java 8 Streams tutorialClick to read: Java 8 Streams tutorial.
  • Data structures: records and DTOs exist to expose their data. Reading order.customer().name() from a record that is only a data carrier is not hiding anything, although a long chain can still be a sign that the data belongs somewhere else.
  • Value types from the JDK: LocalDate.now().plusDays(3).getDayOfWeek() works on immutable values, not on another object's internals.

Common objections

  • "It creates lots of wrapper methods": it can. If Employee gains a delegating method for every field of every object it holds, the design has a different problem - the caller probably needs a different object, or the work belongs elsewhere. Add delegating methods for real questions, such as "who approves", not for raw data.
  • "It hides the structure I need to know": hiding it is the point. The caller depends on the answer, not on how the answer is stored, so the storage can change.
  • "Getters are everywhere in Java": getters are fine. The problem is calling methods on what they return to reach further into the graph.

Summary

In this tutorial we first saw what the Law of Demeter says: a method may call methods only on itself, its fields, its parameters and the objects it creates - not on strangers returned by them. Next we saw why train-wreck chains couple a caller to a whole object structure. We then ran an example in which a getter chain kept sending leave requests to a manager who was on leave, while the version that asked the employee picked up the new rule without a change. We then listed the ways to fix violations, and the cases - fluent APIs, streams, data carriers and value types - where chained calls are fine. Lastly, we answered the common objections.