328-341DeBug/零钱通项目

一、DeBug

// 01
package com.alice.debug_;

import java.util.Scanner;

public class Debug01 {
    public static void main(String[] args) {
        // 1、写好一个简单的程序,如何下断点,只需要鼠标左键点击左边
        // 代码序号的右边,即可出现一个红点。
        // 2、在编程和调试中,breakpoint 指的是程序执行到某一行代码时暂停的位置,
        // 方便开发者检查变量、调用栈等信息。
        // 这里不能run,我们需要的是Debug
        // run的快捷键是Ctrl + Shift + F10
        // debug的快捷键是Shift + F9
        // debug后会在断点处停止,不会执行该断点的代码
        // 3、在Debug窗口会有一些蓝色小箭头的图标,
        // Step Over是逐行执行 F8
        // Step Into是进入到方法体内 F7
        // Force Step Into是强制进入到方法体内 Alt + Shift + F7
        // Step Out是跳出方法 Shift + F8
        // Resume Program 是可以执行到下一个断点 F9
        // 4、断点可以动态的下断点,我们在Debug状态的时候也可以下断点
        // 再次点击断点就会取消这个断点
        // 点击红色小方块就结束整个Debug Stop ‘xxx’ Ctrl + F2
        Scanner scanner = new Scanner(System.in);
        int sum = 0;  // 使用Debug可以看到这些变量的变化
        System.out.print("请输入从0加到哪个数结束:");  // 如果看到Console出现黄色向下箭头闪动说明有输出
        int end = scanner.nextInt();
        for (int i = 0; i < end; i++) {
            sum += i;
            System.out.println("第" + (i + 1) + "次的和为->" + sum);
        }
        System.out.println("...end程序结束end...");
        // 执行到最后一行,程序结束,在Variables窗口中提示Variables are not available变量无法获得。
        // 5、DeBug的好处是,我们拿到别人的代码如果看不懂就可以使用Debug来看
    }
}

//02
package com.alice.debug_;

import java.util.Arrays;
import java.util.Scanner;

public class Debug02 {
    public static void main(String[] args) {
        // 1、数组越界异常
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入int数组的大小:");
        int size = scanner.nextInt();
        int[] arr = new int[size];  // 将鼠标放到arr上面会出现加号,可以获知arr的信息
        for (int i = 0; i < arr.length; i++) {  // 如果这里写成<=出现ArrayIndexOutOfBoundsException
            arr[i] = (int)(Math.random() * 100 + 1);  // 终端会提示哪一行出现异常,点击蓝色字体跳转到这行提示
        }
        System.out.println("当前的int数组为--> " + Arrays.toString(arr));
        System.out.println("程序结束...");
    }
}
//03
package com.alice.debug_;

import java.util.Arrays;
import java.util.Scanner;

public class Debug03 {
    public static void main(String[] args) {
        // 1、创建一个数组,然后使用Arrays.sort()方法排序,想看源码怎么排序的
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入随机生成一维数组的大小:");
        int size = scanner.nextInt();
        int[] arr = new int[size];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int)(Math.random() * 100 + 1);
        }
        System.out.println("得到的随机数组------------>" + Arrays.toString(arr));
        Arrays.sort(arr);  // F7可以跳进方法,但是我们会发现数组已经排好了
        // 那么为什么没有进去?
        // 2、我们可以使用F7旁边的一个红色的向下箭头可以强制跳进去
        // force强制
        // 3、第二种方式是通过配置的方式(推荐)
        // 点击Setting->Build,Execution,Deployment->Debugger->Stepping将Do not step into the
        // classes中的java.*,javax.*取消勾选即可。然后再重新使用F7尝试发现成功,这里老韩也提供了一个文档
        // 由于进入到Arrays.sort()还有一个调用,我们还需要F7追踪
        // 真正帮助我们完成排序的是这个DualPivotQuicksort.sort,还可以继续追,这里还有一个sort(a,left,right,true);
        // Sorts the specified range of the array by Dual-Pivot Quicksort.可以看到使用的算法 快排,后面讲解
        // 可以看到源码非常复杂
        // 目前我们已经追踪到真正的sort排序方法
        // 已经知道是快排然后我们想要回到主方法只需要跳出Shift + F8
        System.out.println("Arrays.sort()排序后的数组->" + Arrays.toString(arr));
    }
}
//04
package com.alice.debug_;

import java.util.Arrays;
import java.util.Scanner;

public class Debug04 {
    public static void main(String[] args) {
        // 快速执行到下一个断点F9,且断点可以在Debug的过程中,动态的下断点
        // 创建一个数组并且排序
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入数组的大小:");
        int size = scanner.nextInt();
        int[] arr = new int[size];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 100 + 1);
        }
        System.out.println("原数组->" + Arrays.toString(arr));
        Arrays.sort(arr);  // 断点1 F9直接执行到下一个断点为止
        System.out.println("现数组->" + Arrays.toString(arr));
        // 很多的打印语句
        System.out.println("ok100");
        System.out.println("ok200");
        System.out.println("ok300");
        System.out.println("ok400");
        System.out.println("ok500");
        System.out.println("ok600");
        System.out.println("ok700");  // 断点2 ,F9到下一个动态下的断点
        System.out.println("ok800");
        System.out.println("ok900");  // 动态下一个断点3
        // 同理下断点可以在自己的代码,java本身的代码都可以下断点
        // tip,下的断点不一定会到这个断点位置停止,因为前面如果有一些逻辑判断不通过可能走不到这个断点,
        // 即,需要看代码本身的业务逻辑,断点需要结合业务逻辑
        // 应用场景:多线程,判断业务逻辑
    }
}
//05
package com.alice.debug_;

public class Debug05 {
    public static void main(String[] args) {
        // 1、课后练习题一
        // 使用断点调试的方法,追踪到下一个对象创建的过程。Person[name,age,构造器...]
        Person alice = new Person("alice", 18);
        // 创建对象的流程
        // 1)加载Person类信息
        /*
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        } 将Person类信息加载
        */
        // 2)初始化 1默认初始化 2显式初始化 3构造器初始化  第二次强制进入直接进入到构造器初始化,前面两部看不到
        // 3)返回对象地址
        System.out.println(alice);  // 直接运行run看不到创建对象的过程,我们想要看到过程,在创建对象这行代码下断点
        /*
            public void println(Object x) {
                String s = String.valueOf(x);
                synchronized (this) {
                    print(s);
                    newLine();
                }
            }
            追
            public static String valueOf(Object obj) {
                return (obj == null) ? "null" : obj.toString();
            }
            追
            @Override
            public String toString() {
                return "Person{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
         */

    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {  // 开始直接F7进入到的是这里,我们想要直接到底层的可以强制进入
        this.name = name;  // 当前name是空,当执行完该语句之后为alice
        this.age = age; // 当前age为0,当执行完成后为18
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//06
package com.alice.debug_;

public class Debug06 {
    public static void main(String[] args) {
        // 动态绑定机制
        A a = new B();
        System.out.println(a.sum());  // 调用方法看运行类型,当前运行类型是B,结果30
        System.out.println(a.sum1());  // 同理,但是属性看当前的,结果20

    }
}

class A {
    public int i = 10;
    public int sum() {  // getI()看运行类型B的
        return getI() + 10;  // 20 + 10 = 30
    }
    public int sum1() {  // A有sum1,i看编译类型A的,返回10 + 10 = 20
        return i + 10;  // 看当前10
    }

    public int getI() {
        return i;
    }
}

class B extends A{  // B中没有sum,但是继承了A类的sum掉A的
    public int i = 20;
    public int getI() {  // B有,返回20
        return i;  // 属性看当前20
    }
}

二、零钱通项目

// 面向过程版
package com.alice.smallchange;

import java.util.Scanner;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class SmallChangeSys {
    public static void main(String[] args) {
        // 1、菜单界面
        // 2、零钱通明细
        //  1)可以将收益入账和消费保存到数组
        //  2)可以使用对象
        //  3)可以使用String拼接  details
        // 3、收益入账
        /*  获取当前时间
            import java.time.LocalDateTime;
            import java.time.format.DateTimeFormatter;

            public class Main {
                public static void main(String[] args) {
                    // 获取当前时间
                    LocalDateTime now = LocalDateTime.now();

                    // 定义格式(年月日 小时分钟)
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm");

                    // 格式化时间
                    String formattedTime = now.format(formatter);
                    System.out.println("当前时间: " + formattedTime);
                }
            }
            字符串+=性能优化
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 10; i++) {
                sb.append("some string");
            }
            String result = sb.toString();
         */
        // 4、消费
        // 定义新变量,保存消费的原因
        // 5、退出
        /*
           改进
                一、用户输入4退出时,给出提示信息"你确定要退出吗?y/n",必须输入正确的y/n,否则循环输入指令,知道输入y或者n。
                    关于这一段代码,老韩给出建议:
                        //老韩建议的代码,以后添加另外的符号,易于扩展,将代码细化,一块代码完成一件事情。
                        if("y".equals(choice) || "n".equals(choice)) {  // 判断输入
                            break;
                        }
                        if(choice.equals("y")) {  // 结束程序
                            loop = false;
                        }
                        //不推荐的写法
                        if("y".equals(choice)) {  // 代码混在一起
                            loop = false;
                            break;
                        } else if ("n".equals(choice)) {
                            break;
                        }
                二、在收益入账和消费的时候,判断金额是否合理,并给出相应的提示。
                    技巧:找不不正确金额的条件,然后给出提示即可,然后就不要执行下面的代码,直接break;
                    生活中:我们要做一件事情的时候一路跟过关斩将,如果遇到某一关不过我们打道回府,如果都通过了就ok;
                    if(money <= 0) {
                        System.out.println("收益入账金额需要大于0");
                        break;
                    }
                    if(money <= 0 || money > balance) {
                        System.out.println("你的消费金额应该在0-"+balance);
                    }
                    这样的代码更加简洁,且易于扩展。
                    以后还需要过关斩将的时候直接继续在后面写if。
                    if(){}
                三、将面向规程的代码修改为面向对象的方法,编写SmallChangeSysOOP.java类,并使用SmallChangeSysApp.java完成测试
         */
        Scanner scanner = new Scanner(System.in);
        boolean noEnd = true;
        String menuChoice = " ";
        String leftAndRightLineOfMenu = "-----------------";
        String leftBlankOfMenu = "             ";
        String titleOfMenu = "零钱通菜单";
        String titleOfDetails = "零钱通明细";
        String titleOfBreak = "退出零钱通";
        // String details = "";  // StringBuilder sb = new StringBuilder();
        StringBuilder details = new StringBuilder();
        String detailsToString = "";
        double balance = 0.0;
        String[] menu = {"零钱通明细", "收益入账", "消费", "退    出"};
        int lengthOfMenu = menu.length;
        String formattedTime = "";
        do {
            System.out.println(leftAndRightLineOfMenu + titleOfMenu + leftAndRightLineOfMenu);
            for (int i = 0; i < lengthOfMenu; i++) {
                System.out.println(leftBlankOfMenu + (i + 1) + " " + menu[i]);
            }
            System.out.print("请选择(1-" + lengthOfMenu + "):");
            menuChoice = scanner.next();
            switch (menuChoice) {
                case "1":
                    System.out.println(leftAndRightLineOfMenu + titleOfDetails +
                            leftAndRightLineOfMenu + detailsToString);
                    break;
                case "2":
                    System.out.print("收益入账多少钱:");
                    double incomePosted = scanner.nextDouble();
                    if (incomePosted <= 0) {
                        System.out.println("收益的钱不能<=0!");
                        break;
                    }
                    balance += incomePosted;
                    // 格式化时间
                    formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
                    String itemIncomePosted = "\n" + "收益入账" + "\t +" + incomePosted + formattedTime +
                                              "\t余额:" + balance;
                    details.append(itemIncomePosted);  // 字符串+=性能问题
                    detailsToString = details.toString();
                    break;
                case "3":
                    System.out.print("消费原因或地点:");
                    String spendingReason = scanner.next();
                    System.out.print("消费花销:");
                    double expense = scanner.nextDouble();
                    if (expense <= 0 || expense > balance) {
                        System.out.println("消费金额不能<=0元或者大于余额!");
                        break;
                    }
                    formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
                    balance -= expense;
                    String itemExpense = "\n" + spendingReason + "\t -" + expense + formattedTime +
                                         "\t余额:" + balance;
                    details.append(itemExpense);  // 字符串+=性能问题
                    detailsToString = details.toString();
                    break;
                case "4":
                    // 用户输入4退出时,给出提示信息"你确定要退出吗?y/n",必须输入正确的y/n,否则循环输入指令,知道输入y或者n。
                    String yesOrNo = "";
                    boolean breakNow = false;
                    while (!breakNow) {  // 无限循环危险结构警告,推荐使用显式循环条件
                        System.out.print("你确定要退出吗?y/n:");
                        yesOrNo = scanner.next();
                        if ("y".equals(yesOrNo) || "n".equals(yesOrNo)) {
                            breakNow = true;
                        }
                    }
                    if ("y".equals(yesOrNo)) {
                        noEnd = false;
                        break;
                    }
                    break;
                default:
                    System.out.println("请正确输入");
            }
        } while (noEnd);
        System.out.println(leftAndRightLineOfMenu + titleOfBreak + leftAndRightLineOfMenu);
    }
}
// 面向对象版
package com.alice.smallchange.oop;

import java.util.Scanner;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class SmallChangeSysOOP {
    Scanner scanner = new Scanner(System.in);
    boolean noEnd = true;
    String menuChoice = " ";
    String leftAndRightLineOfMenu = "-----------------";
    String leftBlankOfMenu = "             ";
    String titleOfMenu = "零钱通菜单";
    String titleOfDetails = "零钱通明细";
    String titleOfBreak = "退出零钱通";
    // String details = "";  // StringBuilder sb = new StringBuilder();
    StringBuilder details = new StringBuilder();
    String detailsToString = "";
    double balance = 0.0;
    String[] menu = {"零钱通明细", "收益入账", "消费", "退    出"};
    int lengthOfMenu = menu.length;
    String formattedTime = "";

    public void printMenu() {
        System.out.println(leftAndRightLineOfMenu + titleOfMenu + leftAndRightLineOfMenu);
        for (int i = 0; i < lengthOfMenu; i++) {
            System.out.println(leftBlankOfMenu + (i + 1) + " " + menu[i]);
        }
        System.out.print("请选择(1-" + lengthOfMenu + "):");
        menuChoice = scanner.next();
    }

    public void printDetails() {
        System.out.println(leftAndRightLineOfMenu + titleOfDetails +
                leftAndRightLineOfMenu + detailsToString);
    }

    public void printIncomePosted() {
        System.out.print("收益入账多少钱:");
        double incomePosted = scanner.nextDouble();
        if (incomePosted <= 0) {
            System.out.println("收益的钱不能<=0!");
            return;
        }
        balance += incomePosted;
        // 格式化时间
        formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
        String itemIncomePosted = "\n" + "收益入账" + "\t +" + incomePosted + formattedTime +
                "\t余额:" + balance;
        details.append(itemIncomePosted);  // 字符串+=性能问题
        detailsToString = details.toString();
    }

    public void printExpense() {
        System.out.print("消费原因或地点:");
        String spendingReason = scanner.next();
        System.out.print("消费花销:");
        double expense = scanner.nextDouble();
        if (expense <= 0 || expense > balance) {
            System.out.println("消费金额不能<=0元或者大于余额!");
            return;
        }
        formattedTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("\tyyyy-MM-dd HH:mm"));
        balance -= expense;
        String itemExpense = "\n" + spendingReason + "\t -" + expense + formattedTime +
                "\t余额:" + balance;
        details.append(itemExpense);  // 字符串+=性能问题
        detailsToString = details.toString();
    }

    public void breakApp() {
        // 用户输入4退出时,给出提示信息"你确定要退出吗?y/n",必须输入正确的y/n,否则循环输入指令,知道输入y或者n。
        String yesOrNo = "";
        boolean breakNow = false;
        while (!breakNow) {  // 无限循环危险结构警告,推荐使用显式循环条件
            System.out.print("你确定要退出吗?y/n:");
            yesOrNo = scanner.next();
            if ("y".equals(yesOrNo) || "n".equals(yesOrNo)) {
                breakNow = true;
            }
        }
        if ("y".equals(yesOrNo)) {
            noEnd = false;
            return;
        }
    }

    public void runMain() {
        do {
            this.printMenu();
            switch (menuChoice) {
                case "1":
                    this.printDetails();
                    break;
                case "2":
                    this.printIncomePosted();
                    break;
                case "3":
                    this.printExpense();
                    break;
                case "4":
                    this.breakApp();
                    break;
                default:
                    System.out.println("请正确输入");
            }
        } while (noEnd);
        System.out.println(leftAndRightLineOfMenu + titleOfBreak + leftAndRightLineOfMenu);
    }
}


main
package com.alice.smallchange.oop;

public class SmallChangeSysApp {
    public static void main(String[] args) {
        new SmallChangeSysOOP().runMain();
    }
}

posted @ 2025-05-08 22:43  请叫我虾  阅读(15)  评论(0)    收藏  举报