Nest classes with care

In Java, you can nest classes within other classes. This feature is very useful when you need it, but it can be easily abused.

When you have a choice, you should declare your nested classes as static. The reason is that non-static nested classes (inner classes) are tightly coupled to the enclosing parent, while static nested classes aren't. This extra coupling can sometimes cause problems. In general, static nested classes are safer than non-static ones, and less prone to error.

Secondly, you should very rarely use deep levels of nesting.

The terminology for nested classes is a bit confusing. Here's a reminder of the hierarchy:

nested class
  static
  inner class (non-static)
    regular, not within a method or constructor
    inside a method or constructor
      anonymous
      local
Some more reminders: Here's a class which sketches all the different types of nested class:
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public final class MakeMovie {

  /**
    Static, since has no need of being attached to a parent instance.
   */
  static final class Actor {
    Actor(String name){
      this.name = name;
    }
    String getName(){ 
      return name; 
    }
    private String name;
  }

  /**
    Non-static (inner) class, since casting will need to know about the 
    movie's data - its name, director, and budget.
  */
  final class Casting {
    void chooseFrom(List<Actor> actors){
      //can reference the parent's data directly:
      if(director.equals("Stanley Kubrick")){
        //elided...
      }
    }
    List<Actor> getSelectedCast(){ 
      return selectedCast; 
    }
    //static void doThis(){} //does not compile, since static
    private List<Actor> selectedCast;
  }
  
  void wrapParty(){
    Timer timer = new Timer();
    //anonymous class - the implementation of TimerTask
    //this is usually how anonymous classes are used - to define a single method
    timer.schedule(
      new TimerTask(){ 
        @Override public void run() {
          //elided...
        };
      },
      new Date()
    );
  }

  void shootScene(final int sceneNumber){
    //local class - this style seems to be rather rare
    class Camera {
      void shoot(){
        //won't compile unless sceneNumber is final:
        System.out.println(sceneNumber);
      }
    }
    Camera camera = new Camera();
    camera.shoot();
  }
  
  //elided...

  private String movieName;
  private String director;
  private BigDecimal budget;

}