← Back to Advanced Java Course | Chapter 6: Design Patterns | Lesson 14 of 14

Java Repository Pattern

The Repository pattern mediates between the domain model and a data storage mechanism, presenting a collection-like interface for accessing domain objects while hiding how they're actually persisted.
Syntax
java
interface Repository<T, ID> {
    T findById(ID id);
    List<T> findAll();
    void save(T entity);
    void delete(ID id);
}

What is the Repository Pattern?

The Repository pattern mediates between the domain model and a data storage mechanism, presenting a collection-like interface for adding, retrieving, and removing domain objects while hiding exactly how or where they're actually persisted.

Example: What is the Repository Pattern?

java
// Import java.util.* so it can be used by its short name
import java.util.*;
// Define the class Main
public class Main {
	// Define the interface Repository
	interface Repository<T> {
		void save(T item);
		List<T> findAll();
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Print a line to the console
		System.out.println("Repository presents a collection-like interface over storage");
	}
}

Repository Interface

A repository interface typically defines standard operations like save, findById, findAll, and delete, often expressed generically so the same interface shape can be reused across different entity types.

Example: Repository Interface

java
// Import java.util.* so it can be used by its short name
import java.util.*;
// Define the class Main
public class Main {
	// Define the interface Repository
	interface Repository<T> {
		void save(T item);
		// Optional wraps a value that may be absent
		Optional<T> findById(int id);
		List<T> findAll();
		void delete(int id);
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Print a line to the console
		System.out.println("Same generic shape reused across entity types");
	}
}

In-Memory Repository Implementation

An in-memory repository implementation, backed by a simple Map or List, is a lightweight way to satisfy the repository interface during development or testing, without requiring a real database connection.

Example: In-Memory Repository Implementation

java
import java.util.*;
public class Main {
	interface Repository<T> { void save(T item); List<T> findAll(); }
	static class InMemoryUserRepository implements Repository<String> {
		List<String> users = new ArrayList<>();
		public void save(String item) { users.add(item); } // backed by a simple List
		public List<String> findAll() { return users; }
	}
	public static void main(String[] args) {
		Repository<String> repo = new InMemoryUserRepository();
		repo.save("Riya");
		System.out.println(repo.findAll());
	}
}

Database-Backed Repository

A database-backed repository implements the same interface using JDBC or another persistence technology to actually store and retrieve data from a relational database, while calling code remains unaware of the difference.

Example: Database-Backed Repository

java
import java.util.*;
public class Main {
	interface Repository<T> { void save(T item); List<T> findAll(); }
	static class JdbcUserRepository implements Repository<String> {
		List<String> simulatedTable = new ArrayList<>(); // stand-in for a real JDBC-backed store
		public void save(String item) { simulatedTable.add(item); } // real version would run an INSERT
		public List<String> findAll() { return simulatedTable; } // real version would run a SELECT
	}
	public static void main(String[] args) {
		Repository<String> repo = new JdbcUserRepository();
		repo.save("Aman");
		System.out.println(repo.findAll());
	}
}

Repository with Spring Data JPA

Spring Data JPA takes the Repository pattern further by generating a working implementation automatically from just an interface definition, even deriving database queries directly from specially named methods like findByName.

Example: Repository with Spring Data JPA

java
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public class Main {
	static class User { String name; }
	interface UserRepository extends JpaRepository<User, Long> {
		List<User> findByName(String name); // implementation generated automatically
	}
	public static void main(String[] args) {
		System.out.println("Spring Data JPA generates the implementation from the interface alone");
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Returning null from findById when nothing is found, instead of an Optional.
  2. Putting business rules inside the repository, when it should only store and load data.
  3. Using a plain HashMap in an in-memory repository shared by several threads, which is not thread-safe.
Chapter Summary
  • Design patterns are proven solutions to common design problems.
  • Creational patterns such as Singleton, Factory, and Builder control object creation, while structural ones such as Adapter, Decorator, Facade, and Proxy organize objects.
  • Behavioral patterns such as Observer, Strategy, Command, and Template Method, plus MVC and Repository, organize how objects interact.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.