第4章 输入、输出和命令行交互
第4章 输入、输出和命令行交互
前几章的代码大多把数据写死在程序里:
intage=18;Stringname="小林";这样能练语法,但不是真正的交互程序。真实程序通常需要从外部接收数据:用户输入姓名、输入成绩、输入菜单选项,程序再根据输入做处理。
这一章要解决三个问题:
- Java 怎么把内容输出给用户看。
- Java 怎么从键盘读取用户输入。
- 输入不合法时程序为什么会崩,以及怎么防。
学完本章后,你就能写简单的命令行交互程序。
一、输出:println 和 print
最常用输出:
System.out.println("Hello Java");println会输出内容,并换行。
System.out.println("第一行");System.out.println("第二行");输出:
第一行 第二行print不换行:
System.out.print("姓名:");System.out.print("小林");输出:
姓名:小林它们的区别:
| 方法 | 是否换行 | 常见用途 |
|---|---|---|
println | 换行 | 输出结果、日志、提示 |
print | 不换行 | 输出输入提示,如请输入姓名: |
比如:
System.out.print("请输入姓名:");用户会在同一行输入。
二、格式化输出:让内容更清楚
字符串拼接可以输出:
Stringname="小林";intage=18;System.out.println("姓名:"+name+",年龄:"+age);也可以用printf:
System.out.printf("姓名:%s,年龄:%d%n",name,age);常见占位符:
| 占位符 | 含义 |
|---|---|
%s | 字符串 |
%d | 整数 |
%f | 小数 |
%.2f | 保留两位小数 |
%n | 换行 |
示例:
doubleprice=19.9;System.out.printf("价格:%.2f元%n",price);输出:
价格:19.90元入门阶段你可以先主要用字符串拼接,遇到金额、平均分这类需要控制小数位的,再用printf。
三、Scanner:从键盘读取输入
Java 读取命令行输入常用Scanner。
importjava.util.Scanner;publicclassInputDemo{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入姓名:");Stringname=scanner.nextLine();System.out.println("你好,"+name);}}拆开看:
importjava.util.Scanner;表示导入 Scanner 类。Java 标准库里有很多类,用到时要导入。
Scannerscanner=newScanner(System.in);创建一个 Scanner,让它从标准输入System.in读取数据。标准输入通常就是键盘。
Stringname=scanner.nextLine();读取用户输入的一整行文本。
四、读取不同类型的数据
读取字符串:
Stringname=scanner.nextLine();读取整数:
intage=scanner.nextInt();读取小数:
doubleheight=scanner.nextDouble();完整示例:
importjava.util.Scanner;publicclassProfileInput{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入姓名:");Stringname=scanner.nextLine();System.out.print("请输入年龄:");intage=scanner.nextInt();System.out.print("请输入身高:");doubleheight=scanner.nextDouble();System.out.println("姓名:"+name);System.out.println("年龄:"+age);System.out.println("身高:"+height);}}运行后,程序会停下来等待用户输入。这和前面写死变量不一样。
五、nextLine 和 nextInt 混用的坑
看这段代码:
Scannerscanner=newScanner(System.in);System.out.print("请输入年龄:");intage=scanner.nextInt();System.out.print("请输入姓名:");Stringname=scanner.nextLine();System.out.println("姓名:"+name);System.out.println("年龄:"+age);你可能发现:输入年龄后,姓名还没来得及输入,程序就结束了。
原因是:nextInt()读取数字,但不会吃掉最后的换行符。后面的nextLine()读到了那个残留换行,于是得到空字符串。
解决方式:在nextInt()后面补一次nextLine()吃掉换行。
System.out.print("请输入年龄:");intage=scanner.nextInt();scanner.nextLine();System.out.print("请输入姓名:");Stringname=scanner.nextLine();另一种方式是所有输入都用nextLine()读取字符串,再自己转换:
System.out.print("请输入年龄:");StringageText=scanner.nextLine();intage=Integer.parseInt(ageText);这种方式更统一,也更适合后面做错误处理。
六、输入不合法会怎样
如果代码是:
intage=scanner.nextInt();用户输入:
abc程序会抛出异常:
InputMismatchException因为abc不能当作整数读取。
如果使用:
StringageText=scanner.nextLine();intage=Integer.parseInt(ageText);用户输入abc,会出现:
NumberFormatException两种本质一样:输入和程序期待的类型不匹配。
第一阶段我们先用简单方式处理:先判断字符串是否像数字。
publicstaticbooleanisInteger(Stringtext){if(text==null||text.isEmpty()){returnfalse;}for(inti=0;i<text.length();i++){charch=text.charAt(i);if(ch<'0'||ch>'9'){returnfalse;}}returntrue;}使用:
System.out.print("请输入年龄:");StringageText=scanner.nextLine();if(!isInteger(ageText)){System.out.println("年龄必须是整数");return;}intage=Integer.parseInt(ageText);这里我们还没系统讲方法,但你可以先看到:把校验逻辑拆成方法,主流程会更清楚。
七、命令行参数和 Scanner 的区别
上一章讲过String[] args:
javaArgsDemo Tom18参数在程序启动时就给好。
Scanner 是程序运行过程中再让用户输入。
对比:
| 方式 | 数据什么时候进入程序 | 适合场景 |
|---|---|---|
String[] args | 启动程序时 | 脚本参数、配置项、一次性命令 |
Scanner | 程序运行中 | 菜单、交互、用户逐步输入 |
命令行参数示例:
publicclassArgsProfile{publicstaticvoidmain(String[]args){if(args.length<2){System.out.println("用法:java ArgsProfile <姓名> <年龄>");return;}Stringname=args[0];intage=Integer.parseInt(args[1]);System.out.println(name+":"+age);}}Scanner 示例:
Scannerscanner=newScanner(System.in);System.out.print("请输入姓名:");Stringname=scanner.nextLine();第一阶段的交互项目主要用 Scanner。
八、做一个注册信息输入程序
需求:
- 输入姓名。
- 输入年龄。
- 输入手机号。
- 判断姓名不能为空。
- 判断年龄是否是整数。
- 判断手机号长度是否为 11。
- 输出注册结果。
代码:
importjava.util.Scanner;publicclassRegisterInputDemo{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入姓名:");Stringname=scanner.nextLine();if(name==null||name.isEmpty()){System.out.println("姓名不能为空");return;}System.out.print("请输入年龄:");StringageText=scanner.nextLine();if(!isInteger(ageText)){System.out.println("年龄必须是整数");return;}intage=Integer.parseInt(ageText);if(age<18){System.out.println("未满18岁,不能注册");return;}System.out.print("请输入手机号:");Stringphone=scanner.nextLine();if(phone==null||phone.length()!=11){System.out.println("手机号必须是11位");return;}System.out.println("注册成功");System.out.println("姓名:"+name);System.out.println("年龄:"+age);System.out.println("手机号:"+phone);}publicstaticbooleanisInteger(Stringtext){if(text==null||text.isEmpty()){returnfalse;}for(inti=0;i<text.length();i++){charch=text.charAt(i);if(ch<'0'||ch>'9'){returnfalse;}}returntrue;}}这段代码已经有一点真实程序的样子了:
- 数据来自用户输入。
- 输入后先校验。
- 不合法就提前 return。
- 合法才继续后续流程。
- 把整数判断拆成方法。
九、为什么要先校验再使用
很多新手会直接:
intage=Integer.parseInt(scanner.nextLine());用户输入正确时没问题。但用户输入abc,程序直接崩。
更稳的流程:
读取原始输入 -> 校验 -> 转换 -> 使用代码:
StringageText=scanner.nextLine();if(!isInteger(ageText)){System.out.println("年龄格式错误");return;}intage=Integer.parseInt(ageText);这个思维非常重要。以后处理网络、文件、数据库也是一样:外部输入永远不要默认可信。
十、常见错误
1. 忘记导入 Scanner
Scannerscanner=newScanner(System.in);如果没有:
importjava.util.Scanner;会编译失败。
2. nextInt 和 nextLine 混用
读取数字后又读取整行,可能读到残留换行。解决方式是补scanner.nextLine(),或者统一用nextLine()。
3. 输入类型不匹配
用户输入 abc,但程序按 int 读取,会异常。
4. 没校验空字符串
Stringname=scanner.nextLine();用户直接回车,name 是空字符串,不是 null。要用:
name.isEmpty()5. 把用户输入当成永远正确
真实程序不能假设用户一定按提示输入。越靠近外部输入,越要防御。
十一、本章练习
写一个程序,输入姓名和城市,输出一句自我介绍。
写一个程序,输入两个整数,输出它们的和。
写一个程序,输入身高和体重,计算 BMI。
写一个程序,输入年龄,判断是否成年。要求年龄不是整数时提示错误。
修改注册程序:手机号必须以
1开头。
十二、本章总结
本章你需要掌握:
println输出并换行。print输出不换行。printf可以格式化输出。Scanner可以读取用户输入。nextLine读取整行。nextInt、nextDouble读取指定类型,但要注意输入不匹配。nextInt和nextLine混用会有换行残留问题。- 命令行参数适合启动时传入,Scanner 适合运行中交互。
- 外部输入必须先校验再使用。
学完这一章,程序已经可以和用户互动了。下一章会讲条件判断,把输入数据转成不同的业务分支。