10.1 Scanner 类:键盘输入的“万能钥匙”

章节总述:本章学习目标

本章我们将学习Java 标准库中四个非常实用的工具类:ScannerDateCalendarMath。它们是Java编程中处理输入、日期时间和数学运算的基石。学完本章,你将能够:

  1. 熟练使用 Scanner 从键盘、文件等不同来源读取各种类型的数据。
  2. 理解并操作日期和时间,掌握 DateCalendar 类的核心用法。
  3. 运用 Math 类进行常见的数学计算,如三角函数、指数、对数、取整等。
  4. 综合运用这些类解决实际问题,为后续学习文件操作、GUI编程等打下基础。

知识点拆解

Scanner 类是 java.util包下的一个工具类,它就像一个“扫描仪”,可以将各种输入源(如键盘、字符串、文件)的数据“扫描”并转换成程序可以处理的类型。

核心要点:

  • 构造方法Scanner(InputStream source) 最常见,用 System.in 作为参数创建从键盘输入的 Scanner 对象。
  • 常用方法
    • next() / nextLine():读取字符串(后者读取整行)。
    • nextInt() / nextDouble() / nextBoolean():读取对应基本类型。
    • hasNextXxx():判断是否还有下一个指定类型的输入。

课堂示例代码

import java.util.Scanner; // 1. 导入 Scanner 类

public class ScannerDemo {
    public static void main(String[] args) {
        // 2. 创建 Scanner 对象,关联标准输入流(键盘)
        Scanner sc = new Scanner(System.in);

        System.out.print("请输入您的姓名:");
        String name = sc.nextLine(); // 读取整行字符串

        System.out.print("请输入您的年龄:");
        int age = sc.nextInt(); // 读取整数

        System.out.print("请输入您的身高(米):");
        double height = sc.nextDouble(); // 读取浮点数

        // 3. 使用读取到的数据
        System.out.println("您好," + name + "!");
        System.out.println("年龄:" + age + ",身高:" + height + "米。");

        // 4. 【重要】关闭 Scanner 对象,释放资源(尤其是读取文件时)
        sc.close();
    }
}

课后易错题解析

【易错点1】nextLine()跟在nextInt()等后面“吞掉”输入

Scanner sc = new Scanner(System.in);
System.out.print("请输入数字:");
int num = sc.nextInt();
System.out.print("请输入字符串:");
String str = sc.nextLine(); // 这里会直接跳过,读取不到!
System.out.println(str);
  • 原因nextInt() 只读取了数字,输入流中残留的换行符 \n 被紧随其后的 nextLine() 读取,导致它认为输入已结束。
  • 解决:在 nextInt() 后多加一句 sc.nextLine(); 来“消耗”掉那个换行符。

【易错点 2】输入类型不匹配导致 InputMismatchException
如果程序期待一个整数,用户却输入了字母,程序会崩溃。

  • 解决:使用hasNextInt()等方法先进行判断。
    if (sc.hasNextInt()) {
        int num = sc.nextInt();
    } else {
        System.out.println("输入的不是整数!");
        sc.next(); // 将错误的输入消耗掉
    }
    

10.2 Date 类和 Calendar 类:与时间对话

知识点拆解

Java早期使用java.util.Date表示特定的瞬间(精确到毫秒),但它的很多方法(如获取年、月)已过时。java.util.Calendar类是一个抽象类,提供了更丰富的日期时间字段操作和计算功能(如加减天数)。

核心要点:

  • Date 类:主要用于获取当前时间或表示一个时间点。new Date()获取当前时间。
  • Calendar 类:通过Calendar.getInstance()获取实例(通常是GregorianCalendar)。使用get(int field)获取字段(年、月、日等),使用set()add()进行设置和计算。
  • 【重点】 月份在Calendar中是从0开始计数的(0代表一月,11代表十二月)。

课堂示例代码

import java.util.Calendar;
import java.util.Date;

public class DateCalendarDemo {
    public static void main(String[] args) {
        // 1. Date 类基本使用
        Date now = new Date();
        System.out.println("当前时间 (Date):" + now);
        System.out.println("毫秒数:" + now.getTime()); // 获取时间戳

        // 2. Calendar 类基本使用
        Calendar cal = Calendar.getInstance(); // 获取 Calendar 实例
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1; // 【注意】月份要 +1
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        System.out.printf("当前时间(Calendar):%d年%d月%d日 %d时\n", year, month, day, hour);

        // 3. Calendar的日期计算
        cal.add(Calendar.DAY_OF_MONTH, 7); // 加7天
        System.out.println("一周后的日期:" + cal.getTime());

        cal.set(2025, Calendar.DECEMBER, 25); // 设置日期(月份可用常量)
        System.out.println("设置的日期:" + cal.getTime());
    }
}

课后易错题解析

【易错点】混淆 DateCalendar 的用法,尤其是月份

  • DategetYear() 返回的是“年份-1900”,getMonth() 返回 0-11,这些方法已过时,不推荐使用。
  • 最佳实践:如果需要获取或操作具体的日期时间字段,统一使用 Calendar 类。Date 更适合作为时间戳或与旧代码交互。

10.3 Math 类:你的随身计算器

知识点拆解

java.lang.Math类提供了执行基本数学运算的静态方法,如指数、对数、平方根、三角函数等。所有方法都是static的,可以直接通过类名调用。

核心要点:

  • 常用常量Math.PI(圆周率)、Math.E(自然对数的底)。
  • 基本运算abs()(绝对值)、max()/min()(最大/最小值)、pow(a, b)(a的b次幂)、sqrt()(平方根)。
  • 取整方法
    • ceil():向上取整(返回>=参数的最小整数)。
    • floor():向下取整(返回<=参数的最大整数)。
    • round():四舍五入(Math.round(11.5)返回12,Math.round(-11.5)返回-11)。
  • 三角函数sin()cos()tan(),参数是弧度制。
  • 随机数Math.random()返回[0.0, 1.0)之间的double值。

课堂示例代码

public class MathDemo {
    public static void main(String[] args) {
        // 1. 基本运算与常量
        System.out.println("PI 的值:" + Math.PI);
        System.out.println("-5 的绝对值:" + Math.abs(-5));
        System.out.println("2 的 10 次方:" + Math.pow(2, 10));
        System.out.println("9 的平方根:" + Math.sqrt(9));

        // 2. 取整操作
        double num = 3.7;
        System.out.println(num + " 向上取整:" + Math.ceil(num)); // 4.0
        System.out.println(num + "向下取整:" + Math.floor(num)); // 3.0
        System.out.println(num + "四舍五入:" + Math.round(num)); // 4

        // 3. 三角函数(角度转弧度:弧度 = 角度 * PI / 180)
        double degree = 60;
        double radians = Math.toRadians(degree); // 角度转弧度
        System.out.println("sin(60°) = " + Math.sin(radians));

        // 4. 生成指定范围的随机整数(例如1-100)
        int randomNum = (int) (Math.random() * 100) + 1;
        System.out.println("1-100的随机数:" + randomNum);
    }
}

课后易错题解析

【易错点】Math.round() 的“四舍五入”规则
Math.round()采用的舍入模式是“四舍六入五成双”(银行家舍入法)的变体,对于 .5 的情况,会向最近的偶数舍入。但在 Math.round() 中,对于正数,.5 总是向上舍入;对于负数,.5 总是向绝对值更大的方向舍入(即向下舍入)。

  • Math.round(11.5) -> 12
  • Math.round(-11.5) -> -11
  • Math.round(-11.6) -> -12
    记住:正数.5向上,负数.5也向上(向零的反方向)

本章小结:核心考点思维导图(文字版)

第10章 常用工具类
├── Scanner类
│   ├── 作用:解析基本类型和字符串的输入
│   ├── 构造:new Scanner(System.in)
│   ├── 方法:nextXxx() / hasNextXxx()
│   └── 【注意】nextLine()与nextXxx()混用的换行符问题
├── Date 与 Calendar 类
│   ├── Date:表示时间点,多用于获取当前时间或时间戳
│   ├── Calendar:日期字段操作和计算(抽象类,getInstance 获取)
│   ├── 核心字段:YEAR, MONTH(0-11), DAY_OF_MONTH, HOUR
│   └── 【重点】月份从0开始,Calendar.MONTH获取后需+1
└── Math类
    ├── 特点:所有方法静态,通过类名调用
    ├── 运算:abs, max/min, pow, sqrt
    ├── 取整:ceil(向上), floor(向下), round(四舍五入)
    ├── 三角:sin/cos/tan(参数为弧度)
    └── 随机:random() [0.0, 1.0)

本章核心:掌握这四个类的核心用途关键方法典型易错点Scanner重在输入流处理,Date/Calendar重在日期时间操作,Math重在数学计算。多敲代码,理解每个方法的行为细节。


习题10:综合编程实战

题1:简易计算器
编写一个程序,使用Scanner读取用户输入的两个数字和一个运算符(+、-、*、/),使用 Math 类的方法(如 pow 用于乘方)实现计算并输出结果。要求能处理除法除数为零的情况。

题2:生日计算器
编写程序,使用Scanner读取用户的出生年月日(年、月、日分别输入),使用 Calendar 类计算并输出:

  1. 你出生那天是星期几?
  2. 你今年(程序运行年份)的生日是星期几?
  3. 你距离100周岁生日还有多少天?

题3:随机点名器
假设班级有10位同学,姓名存储在数组中。编写程序,利用 Math.random() 实现一个随机点名器,每次运行随机选择一位同学并输出其姓名。扩展功能:可以多次运行,且保证在一次程序运行中不会重复点到同一人(直到所有人都被点过一次)。


参考答案代码

习题1 参考答案

import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入第一个数字:");
        double num1 = sc.nextDouble();
        System.out.print("请输入运算符(+, -, *, /, ^):");
        char op = sc.next().charAt(0); // 读取第一个字符作为运算符
        System.out.print("请输入第二个数字:");
        double num2 = sc.nextDouble();

        double result = 0;
        boolean valid = true;

        switch (op) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                if (num2 != 0) {
                    result = num1 / num2;
                } else {
                    System.out.println("错误:除数不能为零!");
                    valid = false;
                }
                break;
            case '^':
                result = Math.pow(num1, num2);
                break;
            default:
                System.out.println("错误:不支持的运算符!");
                valid = false;
        }
        if (valid) {
            System.out.println("计算结果:" + result);
        }
        sc.close();
    }
}

习题2 参考答案

import java.util.Calendar;
import java.util.Scanner;

public class BirthdayCalculator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入出生年份:");
        int birthYear = sc.nextInt();
        System.out.print("请输入出生月份:");
        int birthMonth = sc.nextInt() - 1; // 转换为 Calendar 月份
        System.out.print("请输入出生日期:");
        int birthDay = sc.nextInt();

        Calendar cal = Calendar.getInstance();
        Calendar birthCal = Calendar.getInstance();
        birthCal.set(birthYear, birthMonth, birthDay);

        // 1. 出生那天是星期几
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        int weekDayBorn = birthCal.get(Calendar.DAY_OF_WEEK) - 1; // 周日=1
        System.out.println("你出生那天是:" + weekDays[weekDayBorn]);

        // 2. 今年生日是星期几
        int currentYear = cal.get(Calendar.YEAR);
        Calendar thisYearBirthday = Calendar.getInstance();
        thisYearBirthday.set(currentYear, birthMonth, birthDay);
        int weekDayThisYear = thisYearBirthday.get(Calendar.DAY_OF_WEEK) - 1;
        System.out.println("你今年的生日是:" + weekDays[weekDayThisYear]);

        // 3. 距离 100 周岁生日还有多少天
        Calendar hundredBirthday = Calendar.getInstance();
        hundredBirthday.set(birthYear + 100, birthMonth, birthDay);
        long diffMs = hundredBirthday.getTimeInMillis() - cal.getTimeInMillis();
        long diffDays = diffMs / (1000 * 60 * 60 * 24);
        System.out.println("距离你100周岁生日还有 " + diffDays + " 天。");

        sc.close();
    }
}

习题3 参考答案

import java.util.ArrayList;
import java.util.Arrays;

public class RandomRollCall {
    public static void main(String[] args) {
        // 初始名单
        String[] allStudents = {"张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑十一", "王十二"};
        // 转换为动态列表,便于移除已点名的同学
        ArrayList<String> remainingStudents = new ArrayList<>(Arrays.asList(allStudents));

        System.out.println("--- 随机点名开始 (不重复) ---");
        // 假设要点完所有人
        while (!remainingStudents.isEmpty()) {
            // 生成一个剩余名单范围内的随机索引
            int randomIndex = (int) (Math.random() * remainingStudents.size());
            String selected = remainingStudents.remove(randomIndex); // 移除并获取
            System.out.println("本次点到:" + selected);
            System.out.println("剩余未点同学:" + remainingStudents);
            System.out.println("按回车继续下一轮...");
            try {
                System.in.read(); // 等待用户按回车继续
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("所有同学均已点到!");
    }
}

希望这篇复盘笔记能帮助你巩固第10章的知识。学习编程,理解原理后一定要多动手实践,把书上的例子和习题都自己敲一遍,遇到问题正是加深理解的好机会。加油!

Logo

CANN开发者社区旨在汇聚广大开发者,围绕CANN架构重构、算子开发、部署应用优化等核心方向,展开深度交流与思想碰撞,携手共同促进CANN开放生态突破!

更多推荐