SOLID principles in Java Single Responsibility Open/Closed Liskov's substition Interface Segregation Dependency Inversion