前言
在Java输入输出处理体系中,8.3小节标准输入输出流是入门最常用的IO模块,程序和控制台的交互全部依托Java预设的全局标准流实现。
我们日常写测试代码、接收键盘录入、打印运算结果,都离不开System.in标准输入、System.out标准输出。很多新手只会简单用Scanner,却分不清底层字节流原理、格式化输出占位符用法,本文严格按照课本8.3章节结构拆解:标准输入、Scanner封装、标准输出与格式化输出、实战案例四部分,条理清晰贴合教材内容。
一、什么是Java标准输入输出流
JVM启动时会自动初始化三个静态标准流对象,属于全局唯一资源,无需手动创建、关闭:
System.in:标准输入流,数据源为键盘,底层是InputStream字节输入流
System.out:标准输出流,输出目标为控制台,底层是PrintStream打印流
System.err:标准错误输出流,专门打印异常错误信息,红色字体区分普通输出
8.3.1 标准输入
底层原生System.in使用
System.in是原生字节输入流,直接读取键盘输入的字节数据,原生API使用繁琐,仅适合底层理解:
import java.io.IOException;
public class RawSystemInDemo {
public static void main(String[] args) throws IOException {
System.out.print("请输入单个字符:");
// 读取一个字节
int ch = System.in.read();
System.out.println("你输入的字符:" + (char) ch);
}
}
缺点:
只能读取字节,处理中文极易乱码
无法直接读取整数、浮点数、字符串,需要手动转换
一次只读单个字节,无法接收完整一行输入
因此实际开发中几乎不会直接使用原生System.in,而是借助工具类封装,也就是下面的Scanner。
8.3.2 Scanner类封装标准输入流
Scanner是java.util包下的工具类,专门封装System.in标准输入流,简化各类数据类型的键盘录入,支持读取字符串、数字、布尔值、整行文本。
1. Scanner基础语法
// 绑定标准输入流System.in
Scanner sc = new Scanner(System.in);
2. 常用录入方法
方法作用nextInt()读取整数intnextDouble()读取小数doublenextBoolean()读取布尔值true/falsenext()读取空格分隔的单个字符串nextLine()读取完整一行(包含空格)3. 基础录入示例
import java.util.Scanner;
public class ScannerInputDemo {
public static void main(String[] args) {
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();
System.out.println("=====个人信息====");
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("身高:" + height);
// 释放输入流资源
sc.close();
}
}
注意坑点
先使用nextInt()/nextDouble()再调用nextLine()时,回车换行符会被残留读取,导致空输入;解决方案:读取数字后额外调用一次sc.nextLine()吸收换行。
8.3.3 标准输出和格式化输出
1. 基础输出方法(System.out)
System.out是PrintStream打印流,三个核心输出方法:
print(内容):输出后不换行
println(内容):输出后自动换行
printf(格式字符串, 参数):格式化输出,支持占位符
2. printf格式化占位符(核心重点)
占位符适配数据类型含义%d整数(byte/short/int/long)十进制整数%f浮点float/double小数,默认保留6位小数%s字符串String文本字符串%cchar字符单个字符%bboolean布尔true/false%n无参数自动换行(跨平台兼容)格式化修饰符拓展
%5d:占5个字符宽度,右对齐
%.2f:小数保留2位
%-5d:左对齐,占5字符宽度
8.3.4 实用案例8.1:数据的格式化输出
贴合课本案例,实现学生成绩格式化打印,对齐排版、控制小数精度:
import java.util.Scanner;
/**
* 案例8.1 数据格式化输出:学生成绩表打印
*/
public class FormatPrintCase {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 录入学生信息
System.out.print("请输入学生姓名:");
String name = sc.nextLine();
System.out.print("请输入学号:");
int id = sc.nextInt();
System.out.print("请输入语文成绩:");
double chinese = sc.nextDouble();
System.out.print("请输入数学成绩:");
double math = sc.nextDouble();
double avg = (chinese + math) / 2;
// 格式化表格输出
System.out.println("====================学生成绩====================");
System.out.printf("%-10s %-8s %-8s %-8s %-8s%n", "姓名", "学号", "语文", "数学", "平均分");
System.out.printf("%-10s %-8d %-8.1f %-8.1f %-8.2f%n", name, id, chinese, math, avg);
System.out.println("==================================================");
sc.close();
}
}
运行效果示例:
====================学生成绩====================
姓名 学号 语文 数学 平均分
张三 1001 92.5 88.0 90.25
==================================================
三、易错点总结
原生System.in不推荐直接使用:处理中文、多类型数据极其麻烦,优先Scanner封装;
Scanner换行符陷阱:数字读取后换行残留问题,补充一次nextLine()清空缓冲;
printf小数精度:默认保留6位,通过%.Nf手动控制保留N位小数;
标准流关闭问题:System.in/out为全局JVM资源,开发测试无需手动关闭Scanner,生产环境可按需关闭;
System.err作用:异常信息用err输出,和普通out打印区分,方便日志排查。
四、课后拓展思考
对比原生System.in.read()和Scanner录入的优劣?
printf中%d和%5d、%-5d排版区别是什么?
如果输入中文姓名,使用next()和nextLine()分别会出现什么问题?
文末小贴士
标准输入输出流是整个Java IO章节的敲门砖,后续学习文件字节流、字符流时,PrintWriter、BufferedReader的设计思路和标准流完全相通,吃透能大幅降低后续IO学习难度。