Java 小例子:图书馆课程设计(Java 8 版)

用 Java 模拟一个图书馆。包括创建图书、创建读者、借书、还书、列出所有图书、列出所有读者、列出已借出的图书、列出过期未还的图书等功能。每个读者最多只能借 3 本书,每个书最多只能借 3 个星期,超过就算过期。

这个例子跟 http://blog.csdn.net/yidinghe/article/details/3940437 相比,增加了 Java 8 特有的语法,包括:Lambda 表达式,java.time 日期 API,streaming API 等。功能也比前者稍微完善了些,体积有所减小。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 图书馆例子 Java 8 版本
 * created at 2014/11/4
 *
 * @author Yiding
 */
public class LibraryManager {

    public static final Scanner SCANNER = new Scanner(System.in);

    public static final String NUMBERS_ONLY = "^\\d+$"; // 表示只允许输入数字

    public static final String ANY_CONTENT = "^\\S+$";  // 表示可以输入任何内容

    public static void main(String[] args) {
        new LibraryManager().start();
    }

    ////////////////////////////////////////////////////////////////

    private Library library = new Library();

    private ArrayList<Command> commands = new ArrayList<>();

    private String mainMenu;

    /**
     * 构造方法
     */
    public LibraryManager() {
        initCommands();
        initStudents();
        initBooks();
    }

    private void initBooks() {
        this.library.addBook("论程序员的自我修养", "带鱼", BookType.科学类.toString());
        this.library.addBook("印度四大名著全集", "阿达木", BookType.文学类.toString());
        this.library.addBook("睡眠的好处", "程序员阿迪", BookType.科学类.toString());
        this.library.addBook("架构师2014年10月刊", "美丽女人网", BookType.杂志.toString());
    }

    private void initStudents() {
        this.library.students.add(new Student("张三"));
        this.library.students.add(new Student("李四"));
        this.library.students.add(new Student("王五"));
    }

    /**
     * 初始化命令和主菜单
     */
    private void initCommands() {
        addCommand(new ListCommand<>("所有图书:", () -> library.books), "查询所有图书");
        addCommand(new ListCommand<>("所有学生:", () -> library.students), "查询所有学生");
        addCommand(new AddBookCommand(), "添加图书");
        addCommand(new DeleteBookCommand(), "删除图书");
        addCommand(new BorrowBookCommand(), "借阅图书");
        addCommand(new ReturnBookCommand(), "归还图书");
        addCommand(new ListCommand<>("所有借阅过期的图书:", library::expiredBooks), "查询借阅过期的图书");
        addCommand(new ExitCommand(), "退出");

        this.mainMenu = toMenu("请输入命令", this.commands);
    }

    private void addCommand(Command command, String title) {
        command.title = title;
        this.commands.add(command);
    }

    /**
     * 开始执行交互
     */
    private void start() {
        CommandResult result;

        // 在 while 条件中判断命令的执行结果是否表示要退出程序
        // 只有 ExitCommand 的执行结果是 CommandResult.EXIT
        do {

            try {
                String command = prompt(mainMenu, NUMBERS_ONLY); // 选择命令
                result = executeCommand(command);                // 执行命令
            } catch (CommandCancelException e) {
                result = CommandResult.FAIL;
            }

            System.out.println(result.prompt + "\n");
        } while (result != CommandResult.EXIT);
    }

    /**
     * 打印一条提示消息并返回用户的输入
     *
     * @param prompt  提示消息
     * @param pattern 指定格式,如果用户的输入不符合格式则会反复提示重新输入。为空则不检查用户输入
     *
     * @return 用户的输入
     */
    private String prompt(String prompt, String pattern) {
        String userInput;

        // 在 while 条件中判断用户输入的内容是否符合 pattern 指定的格式
        // 如果 pattern 为 null 则不做判断
        do {
            System.out.print(prompt);
            userInput = SCANNER.nextLine();

            // 用户直接回车时,表示取消命令执行
            if (userInput.equals("")) {
                throw new CommandCancelException();
            }

        } while (pattern != null && !userInput.matches(pattern));

        return userInput;
    }

    // 打印一组选项并返回用户选择的选项内容
    private String prompt(String prompt, List<?> options) {
        int index = promptIndex(prompt, options);
        return options.get(index - 1).toString();
    }

    // 打印一组选项并返回用户选择的位置
    private int promptIndex(String prompt, List<?> options) {
        String menu = toMenu(prompt, options);
        int index;

        do {
            index = Integer.parseInt(prompt(menu, NUMBERS_ONLY));
        } while (index == 0 || index > options.size());

        return index;
    }

    /**
     * 生成菜单内容
     *
     * @param prompt  提示,在列出所有选项后打印出来
     * @param options 选项
     *
     * @return 主菜单内容
     */
    private <T> String toMenu(String prompt, List<T> options) {
        final ArrayList<String> lines = new ArrayList<>();
        final AtomicInteger counter = new AtomicInteger();

        options.forEach((t) -> {
            int index = counter.incrementAndGet();
            String line = index + ": " + t.toString();
            lines.add(line);
        });

        return String.join("\n", lines) + "\n" + prompt + "(1-" + lines.size() + "):";
    }

    /**
     * 执行用户命令
     *
     * @param command 用户命令序号
     *
     * @return 执行结果
     */
    private CommandResult executeCommand(String command) {
        int index = Integer.parseInt(command);

        if (index > 0 && index <= commands.size()) {
            return commands.get(index - 1).execute();
        } else {
            return CommandResult.OK;
        }
    }

    ////////////////////////////////////////////////////////////////

    static enum CommandResult {
        OK("命令已完成。"), FAIL("命令已取消。"), EXIT("");

        public String prompt;   // 在每个命令结束时打印出来

        CommandResult(String prompt) {
            this.prompt = prompt;
        }

    }

    static enum BookType {文学类, 科学类, 杂志}

    // 表示用户取消命令的异常
    static class CommandCancelException extends RuntimeException {

    }

    static class Book {

        public static final int EXPIRE_BORROW_DAYS = 21;

        public String name;

        public String author;

        public String type;

        public String borrowedBy;

        public String borrowDate;

        Book(String name, String author, String type) {
            this.name = name;
            this.author = author;
            this.type = type;
        }

        public boolean isBorrowed() {
            return this.borrowedBy != null;
        }

        @Override
        public String toString() {
            return name + ",作者:" + author + "," + type +
                    (isBorrowed() ? " -- 已被'" + borrowedBy + "'于" + borrowDate + "借出" : "");
        }

        public boolean isExpired() {
            if (!isBorrowed()) {
                return false;
            }

            // 从当前时间反推过期的借阅时间。如果实际借阅时间在过期的借阅时间之前,则表示过期了
            LocalDate maxBorrowDate = LocalDate.now().minus(EXPIRE_BORROW_DAYS, ChronoUnit.DAYS);
            String maxBorrowDateStr = DateTimeFormatter.ofPattern("yyyyMMdd").format(maxBorrowDate);
            return this.borrowDate.compareTo(maxBorrowDateStr) < 0;
        }
    }

    static class Student {

        public static final int MAX_BORROW = 3;

        public String name;

        Student(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    ////////////////////////////////////////////////////////////////

    class Library {

        private List<Book> books = new ArrayList<>();

        private List<Student> students = new ArrayList<>();

        /**
         * 添加书籍
         *
         * @param bookName 书名
         * @param author   作者
         * @param type     类型
         *
         * @return 执行结果
         */
        public CommandResult addBook(String bookName, String author, String type) {
            if (books.stream().anyMatch((b) -> b.name.equals(bookName))) {
                System.out.println("添加失败:书名已存在");
                return CommandResult.FAIL;
            }

            this.books.add(new Book(bookName, author, type));
            return CommandResult.OK;
        }

        public List<Book> availableBooks() {
            return this.books.stream().filter((b) -> !b.isBorrowed()).collect(Collectors.toList());
        }

        public List<Book> borrowedBooks() {
            return this.books.stream().filter(Book::isBorrowed).collect(Collectors.toList());
        }

        public List<Book> expiredBooks() {
            return this.books.stream().filter(Book::isExpired).collect(Collectors.toList());
        }

        /**
         * 删除书籍
         *
         * @param index 序号
         *
         * @return 执行结果
         */
        public CommandResult deleteBook(int index) {
            this.books.remove(index);
            return CommandResult.OK;
        }

        public int countBorrowedBooks(String student) {
            return (int) this.books.stream().filter((b) -> student.equals(b.borrowedBy)).count();
        }
    }

    ////////////////////////////////////////////////////////////////

    /**
     * 表示命令的抽象类
     */
    static abstract class Command {

        public String title;  // 命令标题,将显示在主菜单中

        abstract CommandResult execute();

        @Override
        public String toString() {
            return title;
        }
    }

    // 列出满足要求的对象
    class ListCommand<T> extends Command {

        private Supplier<List<T>> supplier; // 查询满足要求的对象的方法

        private String title;               // 输出标题

        ListCommand(String title, Supplier<List<T>> supplier) {
            this.title = title;
            this.supplier = supplier;
        }

        @Override
        CommandResult execute() {
            System.out.println("\n" + title);
            supplier.get().forEach(System.out::println);
            return CommandResult.OK;
        }
    }

    // 添加图书
    class AddBookCommand extends Command {

        @Override
        CommandResult execute() {
            return library.addBook(
                    prompt("请输入书名:", ANY_CONTENT),
                    prompt("请输入作者:", ANY_CONTENT),
                    prompt("请选择书籍类型:", Arrays.asList(BookType.values()))
            );
        }
    }

    // 删除图书
    class DeleteBookCommand extends Command {

        @Override
        CommandResult execute() {
            if (library.books.isEmpty()) {
                System.out.println("没有可删除的书籍。");
                return CommandResult.FAIL;
            }

            int index = promptIndex("请选择书籍序号", library.books);
            return library.deleteBook(index - 1);
        }
    }

    // 借阅图书
    class BorrowBookCommand extends Command {

        @Override
        CommandResult execute() {
            List<Book> availableBooks = library.availableBooks();
            if (availableBooks.isEmpty()) {
                System.out.println("没有可借阅的图书。");
                return CommandResult.FAIL;
            }

            int index = promptIndex("请选择要借阅的图书", availableBooks);
            Book book = availableBooks.get(index - 1);

            String student = prompt("请选择借阅者:", library.students);
            if (library.countBorrowedBooks(student) >= Student.MAX_BORROW) {
                System.out.println("该同学不能借阅更多图书了。");
                return CommandResult.FAIL;
            }

            String bDate = prompt("请输入借阅日期(YYYYMMDD):", "^\\d{8}$");

            book.borrowedBy = student;
            book.borrowDate = bDate;
            return CommandResult.OK;
        }
    }

    // 归还图书
    class ReturnBookCommand extends Command {

        @Override
        CommandResult execute() {
            List<Book> borrowedBooks = library.borrowedBooks();
            if (borrowedBooks.isEmpty()) {
                System.out.println("没有图书需要归还。");
                return CommandResult.FAIL;
            }

            int index = promptIndex("请选择已借阅的图书", borrowedBooks);
            Book book = borrowedBooks.get(index - 1);
            book.borrowedBy = null;
            book.borrowDate = null;
            System.out.println("图书已归还。");
            return CommandResult.OK;
        }
    }

    // 退出程序
    class ExitCommand extends Command {

        @Override
        CommandResult execute() {
            return CommandResult.EXIT;
        }
    }
}
时间: 2024-11-07 16:46:26

Java 小例子:图书馆课程设计(Java 8 版)的相关文章

java 小例子

1.创建第一个java web例子 mac 下 使用eclipse创建第一个web页面,很简单  file->new->web project 会出现完整的java web项目: 2.在jsp页面加入后台java类的方法,并显示在页面上 a.创建一个java类 在src上点击右键,new->class  创建一个java类,Demo类,创建一个方法 getHello,如下所示: package tests; public class Demo { public String GetHel

由java小例子到针对(面向)接口编程

在进行Java编程中经常用到以下类似的代码, List<String> strs = new ArrayList<String>(); 只知这是多态,像是一种规范而不知为何如此. 编程时针对超类型(父类)进行编程,也就是说变量的声明类型(或方法的返回类型)是超类型,而不是具体的某个子类.超类型中的各个方法的具体实现不在超类型中,而是在各个子类中.这样在程序执行时可以根据实际状况执行到真正的(某个子类)行为.这样带来的好处是,我们在声明一个变量时无需关心以后执行时的真正的数据类型是哪

Java小例子——穷举质数,求平方和,求质因子。

求平方和 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public static void main(String[] args) throws IOException     {         int n;         String s;         BufferedReader buf;         buf=new BufferedReader(new In

java小知识点(一)---Java中获取键盘输入值的三种方法

Java中获取键盘输入值的三种方法   程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值的现成函数!Java没有提供这样的函数也不代表遇到这种情况我们就束手无策,请你看以下三种解决方法吧:   以下将列出几种方法:   方法一:从控制台接收一个字符,然后将其打印出来   publicstatic void main(String [] args) throws IOException{   Sys

小例子: ping本地网络(鸟哥版)

#!/bin/bash :<<NNNNNNN Use ping command to check the Local Area Network\'s PC state. 检查局域网络上的机器是否畅通.THU07182013 NNNNNNN PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH network="192.168.1"              #

课程设计2 终结版-未测试

公司项目ok了,抽空写完代码,苦于win2000对磁盘有保护,不能直接用int13h,无法测试.代码虽然完成,还要过几天把dos环境塔好再测试.代码反正放这了. 让博客园帮我云存储下.对磁盘结构了解也不多,不知道这代码跑出来是何种结果.至少在主界面输入f3是要屏蔽的. 代码如下: ;   display system time. press f1 to change the color displayed, press esc to return main list. f3 exit;    c

14-9-11 C/C++课程设计--图书馆管理系---&lt;time.h&gt;中时间数据类型的学习记录

小学期C++课程设计需要做一个图书馆管理系统,需要获取当前时间和进行时间运算,在网上找了些资料自学了一下,总结如下: 1.获取日历时间: C++中时间原型为日历时间(Calender Time),表示当前时间和某一固定时间相差的秒数. 定义如下:             #typedef long time_t; 也就是说,日历时间实际上是一个长整形的数据.使用time()函数获取当前的日历时间,              time_t time(NUL); 其返回值就是当前的日历时间. 2.将

freemarker入门小例子

我用freemarker做了两个小例子,主要的东西是:两个Test文件,一个Animal实体类,一个ftl模板---freemarker的模板,我使用maven做的java工程案例.主要结构内容如下图: 注意:需要导入freemarker的jar包: 1.首先我们先来了解一下freemarker的概念: freeMarker概述: FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写: FreeMarker被设计用来生成HTML Web页面,特别是基于MVC

(转)《深入理解java虚拟机》学习笔记2——Java内存溢出实例

通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收实例对象,就会在对象数量达到堆最大容量时产生OutOfMemoryError异常. 想要方便快速地产生堆溢出,要使用如下java虚拟机参数:-Xms10m(最小堆内存为10MB),-Xmx10m(最大堆内存为10MB,最小堆内存和最大堆内存相同是为了避免堆动态扩展),-XX:+HeapDumpOnO