Step 3: Store books behind an interface
Define a BookRepository interface: add a book, find by ISBN, search by text, list all. Then write InMemoryBookRepository using a LinkedHashMap (keeps insertion order). The rest of the application will only know the interface, so later you can swap in a database version without touching the rules. Optional makes "maybe there is no such book" explicit instead of returning null.
ExampleJava
import java.util.*;
public class Main {
static class Book {
final String isbn, title, author;
boolean available = true;
Book(String isbn, String title, String author) { this.isbn = isbn; this.title = title; this.author = author; }
public String toString() { return title + (available ? "" : " (on loan)"); }
}
// The contract: the rest of the app depends on this, not on how books are stored.
interface BookRepository {
void add(Book book);
Optional<Book> findByIsbn(String isbn);
List<Book> search(String text);
List<Book> all();
}
static class InMemoryBookRepository implements BookRepository {
private final Map<String, Book> books = new LinkedHashMap<>();
public void add(Book book) { books.put(book.isbn, book); }
public Optional<Book> findByIsbn(String isbn) { return Optional.ofNullable(books.get(isbn)); }
public List<Book> search(String text) {
String t = text.toLowerCase();
List<Book> result = new ArrayList<>();
for (Book b : books.values()) {
if (b.title.toLowerCase().contains(t) || b.author.toLowerCase().contains(t)) result.add(b);
}
return result;
}
public List<Book> all() { return new ArrayList<>(books.values()); }
}
public static void main(String[] args) {
BookRepository repo = new InMemoryBookRepository();
repo.add(new Book("1", "Clean Code", "Robert Martin"));
repo.add(new Book("2", "The Pragmatic Programmer", "Hunt and Thomas"));
repo.add(new Book("3", "Refactoring", "Martin Fowler"));
System.out.println(repo.all().size() + " books");
System.out.println(repo.findByIsbn("2").map(b -> b.title).orElse("not found"));
System.out.println(repo.findByIsbn("9").map(b -> b.title).orElse("not found"));
System.out.println(repo.search("martin"));
}
}Output
3 books The Pragmatic Programmer not found [Clean Code, Refactoring]
findByIsbn("9") returned the fallback text because the Optional was empty. Search is case-insensitive and matches the title or the author.
Quick check
What does returning Optional<Book> tell the caller?
Finish the quick check (and any code exercise) to complete this lesson, or mark it done yourself.
Tip: use the left and right arrow keys to move between lessons.