Java 学习笔记:输入输出 + 方法
一、键盘输入(Scanner)
1. 基本模板
java
import java.util.Scanner; // 别忘了导包!!
public class InputDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in); // 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("你好," + name);
System.out.println("年龄:" + age + ",身高:" + height);
sc.close();
}
}
2. 常用方法对照表
| 方法 | 读入类型 | 会读空格吗 | 会读换行吗 |
|---|---|---|---|
nextInt() / nextDouble() |
int / double | 否 | 否(换行留在缓冲区) |
next() |
String | 否(遇到空格停) | 否 |
nextLine() |
String | 是 | 是(读走换行) |
3. ⚠️ 容易出错的位置(血泪版)
坑 1:nextInt() 后紧接 nextLine(),第二行读到空串
这是本章最高频的 bug!输入数字后按的回车(\n)还留在缓冲区里,nextLine() 会把它当成一行直接读走。
java
int num = sc.nextInt(); // 输入 100,回车被留在缓冲区
String str = sc.nextLine(); // 直接读到那个回车 → str 是 "",不是你想要的内容!
修复方法(三选一):
java
// 方法1:先吃掉那个回车
int num = sc.nextInt();
sc.nextLine(); // 空跑一次,清掉换行
String str = sc.nextLine();
// 方法2:全程都用 nextLine(),读进来再自己转换
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
// 方法3:全部用 next()(但注意它不读空格)
坑 2:输入类型不匹配 → InputMismatchException
java
int age = sc.nextInt();
// 如果你在键盘上输入了 abc 或 12.5,直接程序崩溃
学生感悟:测试时手滑输错一个字符,红字报错闪一脸,其实不是代码逻辑错,是输入类型 和方法类型没对上。
坑 3:忘了导包
java
// 报错:找不到符号 Scanner
Scanner sc = new Scanner(System.in);
// ✅ 必须在文件最上面写:import java.util.Scanner;
坑 4:中文输入乱码(控制台)
控制台默认编码和程序编码不一致时,中文会变问号。IntelliJ IDEA 可在 Run Configuration → VM options 加:
-Dfile.encoding=UTF-8
二、输出(System.out)
1. 三种打印方式
java
public class OutputDemo {
public static void main(String[] args) {
System.out.print("A"); // 打印后不换行
System.out.print("B"); // 紧接在后面
System.out.println("C"); // 打印后换行
// 输出:ABC
int age = 18;
System.out.println("age = " + age); // 字符串拼接(最常用)
System.out.printf("age = %d\n", age); // 格式化输出(注意要自己加 \n)
System.out.format("age = %d%n", age); // 和 printf 等价,%n 自动换行
}
}
2. 常用格式符(printf / format)
| 格式符 | 含义 | 例子 | 输出 |
|---|---|---|---|
%d |
整数 | printf("%d", 18) |
18 |
%f |
浮点数 | printf("%.2f", 3.14159) |
3.14 |
%s |
字符串 | printf("%s", "hello") |
hello |
%c |
字符 | printf("%c", 'A') |
A |
%% |
输出一个百分号 | printf("%d%%", 95) |
95% |
宽度与对齐:
java
System.out.printf("[%5d]%n", 42); // [ 42] 右对齐,总宽5
System.out.printf("[%-5d]%n", 42); // [42 ] 左对齐
System.out.printf("%8.2f%n", 3.14159);// [ 3.14]
3. ⚠️ 容易出错的位置
坑 1:%d 配 double、%f 配 int 会异常
java
double d = 3.14;
System.out.printf("%d", d);
// 报错:java.util.IllegalFormatConversionException
// %d 只能配整数类型,浮点数要用 %f
坑 2:printf 不会自动换行
java
System.out.printf("abc"); // 后面不会换行,接着输出的内容会连在一起
// ✅ 记得加 \n 或者最后用一次 println
坑 3:println(1 + 2) 和 println("1" + 2) 完全不同
java
System.out.println(1 + 2); // 3 (先算加法)
System.out.println("1" + 2); // 12 (字符串拼接)
System.out.println("结果:" + 1 + 2); // 结果:12
System.out.println("结果:" + (1 + 2)); // 结果:3
这个坑考试必考,工作也常踩:一旦表达式里出现字符串,
+就变成拼接。
三、文件输入输出(了解版)
1. 写文件(字符)
java
import java.io.FileWriter;
import java.io.IOException;
public class WriteFile {
public static void main(String[] args) {
// 第二个参数 true = 追加写入;false/省略 = 覆盖
try (FileWriter fw = new FileWriter("out.txt", true)) {
fw.write("第一行\n");
fw.write("第二行\n");
} catch (IOException e) { // 必须捕获或声明抛出
e.printStackTrace();
}
}
}
2. 读文件(按行读,推荐 BufferedReader)
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("out.txt"))) {
String line;
while ((line = br.readLine()) != null) { // 读到文件末尾返回 null
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. ⚠️ 容易出错的位置
坑 1:路径写法
java
new FileReader("out.txt"); // 相对路径:相对于项目工作目录(容易找不到文件)
new FileReader("src/out.txt"); // 很多 IDE 里文件实际在 src 下
new FileReader("C:\\data\\out.txt"); // Windows 绝对路径,反斜杠要转义 \\
// 新手最常见报错:FileNotFoundException: out.txt (系统找不到指定的文件)
坑 2:流没关闭 / 编码不一致
- 老写法要在
finally里关闭,容易忘 → 优先用try (... ) { }自动关闭(Java 7+)。 FileReader/FileWriter默认用系统编码,读写中文时两边编码要一致,否则乱码。稳妥做法用InputStreamReader(fis, StandardCharsets.UTF_8)。
坑 3:readLine() 返回 null 判断写错
java
String line = br.readLine();
while (line != null) { // ✅ 正确写法
System.out.println(line);
line = br.readLine(); // 必须再读一次,否则死循环
}
四、方法(Method / 函数)
1. 为什么用方法?
- 复用:写一次,多处调用
- 分工:一个方法只干一件事,代码才看得懂
2. 定义与调用的格式
java
public class MethodDemo {
// 定义:返回类型 方法名(参数类型 参数名, ...) { 方法体 }
public static int add(int a, int b) {
int sum = a + b;
return sum; // 把结果交还给调用者
}
public static void sayHello(String name) { // void = 不返回任何值
System.out.println("你好," + name);
}
public static void main(String[] args) {
int result = add(3, 5); // 调用:实参 3 和 5 传给形参 a 和 b
System.out.println(result); // 8
sayHello("小明"); // void 方法直接调用,前面不能接 =
// int x = sayHello("小明"); // ❌ 编译错误:void 不能赋值
}
}
术语别搞混:
- 形参(形式参数) :定义在方法括号里的,如
int a - 实参(实际参数) :调用时传入的,如
add(3, 5)里的3 - 返回值 :
return后面的值,会回传给调用者
3. 方法的执行流程(画图理解)
text
main 调用 add(3, 5)
│
▼
进入 add:a=3, b=5
│
▼
sum = 8,执行 return sum
│
▼
回到 main,result = 8 ← 方法执行完,里面的局部变量 a、b、sum 全部销毁
4. 方法重载(Overload)
同一个类里,方法名相同,但参数列表不同(个数不同 / 类型不同 / 顺序不同)。
java
public class OverloadDemo {
public static int add(int a, int b) {
return a + b;
}
public static double add(double a, double b) {
return a + b;
}
public static int add(int a, int b, int c) {
return a + b + c;
}
public static void main(String[] args) {
System.out.println(add(1, 2)); // 调的是 int 版 → 3
System.out.println(add(1.5, 2.5)); // 调的是 double 版 → 4.0
System.out.println(add(1, 2, 3)); // 调的是三参数版 → 6
}
}
5. ⚠️ 容易出错的位置
坑 1:void 方法里写了 return 值; / 有返回值的方法漏写 return
java
public static void print1() {
return 1; // ❌ 编译错误:void 方法不能返回值
}
public static int print2() {
System.out.println("hi");
// ❌ 编译错误:missing return statement(方法声明了 int 就必须 return)
}
坑 2:return 后面还有代码(不可达代码)
java
public static int f() {
return 1;
System.out.println("end"); // ❌ unreachable code,编译不过
}
坑 3:形参和实参的数量、类型对不上
java
public static int add(int a, int b) { ... }
add(1, 2, 3); // ❌ 实参多了
add(1); // ❌ 实参少了
add("1", 2); // ❌ 类型不对(而且 String "1" 不会自动变 int)
add(1.5, 2.5); // ❌ 1.5 是 double,会编译报错(不会自动帮你转)
Java 很严格:int 能自动变 double,但 double 不能自动变 int。
坑 4:仅返回类型不同,不算重载
java
public static int f(int a) { return 1; }
public static double f(int a) { return 2.0; } // ❌ 编译错误
// 方法名和参数列表完全一样,只改返回类型是不被允许的
坑 5:局部变量没初始化就使用
java
public static void f() {
int x; // 声明了但没赋值
System.out.println(x); // ❌ 编译错误:variable x might not have been initialized
}
坑 6:main 是 static,直接调非 static 方法会报错
java
public class Demo {
public void hello() { // 没有 static
System.out.println("hi");
}
public static void main(String[] args) {
hello(); // ❌ 编译错误:non-static method cannot be referenced
// ✅ 两种修法:
// 1) 把 hello 加上 static
// 2) new Demo().hello(); 先造对象再调
}
}
坑 7:整数除法把小数吃了
java
public static double avg(int a, int b) {
return (a + b) / 2; // a=3, b=4 → (7)/2 = 3(int 除法),不是 3.5!
}
// ✅ 改成:return (a + b) / 2.0; 或 (double)(a + b) / 2;
坑 8:方法里改形参,不会影响外面的变量
java
public static void change(int n) {
n = 100;
}
public static void main(String[] args) {
int x = 1;
change(x);
System.out.println(x); // 仍是 1!基本类型是"值传递",改的是副本
}
五、综合小案例:成绩录入统计
把输入、输出、方法串起来:
java
import java.util.Scanner;
public class ScoreSystem {
// 方法:求平均分
public static double average(int[] scores) {
int sum = 0;
for (int s : scores) {
sum += s;
}
return (double) sum / scores.length; // 注意转 double,否则整数除法
}
// 方法:求最高分
public static int max(int[] scores) {
int m = scores[0];
for (int s : scores) {
if (s > m) m = s;
}
return m;
}
// 方法:根据分数返回等级
public static char grade(int score) {
if (score >= 90) return 'A';
else if (score >= 80) return 'B';
else if (score >= 60) return 'C';
else return 'D';
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入学生人数:");
int n = sc.nextInt();
int[] scores = new int[n];
for (int i = 0; i < n; i++) {
System.out.print("请输入第 " + (i + 1) + " 个学生的成绩:");
scores[i] = sc.nextInt();
}
System.out.printf("平均分:%.1f%n", average(scores));
System.out.println("最高分:" + max(scores));
for (int i = 0; i < n; i++) {
System.out.printf("第%d名 %d分 等级 %c%n",
i + 1, scores[i], grade(scores[i]));
}
sc.close();
}
}
运行示例:
text
请输入学生人数:3
请输入第 1 个学生的成绩:92
请输入第 2 个学生的成绩:75
请输入第 3 个学生的成绩:58
平均分:75.0
最高分:92
第1名 92分 等级 A
第2名 75分 等级 C
第3名 58分 等级 D
六、易错点速查清单(写作业前过一遍)
| # | 检查项 | 后果 |
|---|---|---|
| 1 | import java.util.Scanner; 写了吗 |
找不到符号 Scanner |
| 2 | nextInt() 后接 nextLine(),中间清回车了吗 |
读到空字符串 |
| 3 | 输入内容和方法类型匹配吗(整数不能用 nextDouble 之外的类型乱输) | InputMismatchException |
| 4 | printf 的 %d/%f/%s 和实参类型对上了吗 |
IllegalFormatConversionException |
| 5 | 字符串参与的 + 是拼接还是加法? |
结果变成 "12" |
| 6 | printf 加 \n 了吗 |
输出全挤一行 |
| 7 | 声明了返回类型就 return 了吗?void 里返回值了吗 |
编译错误 |
| 8 | return 后面还有语句吗 |
unreachable code |
| 9 | 形参、实参的个数和类型一致吗 | 编译错误 |
| 10 | 方法重载看的是参数列表,不是返回类型 | 编译错误 |
| 11 | 局部变量初始化了吗 | 编译错误 |
| 12 | static 方法里能直接调非 static 方法吗 |
编译错误 |
| 13 | 两数相除想保留小数,除数或被除数转 double 了吗 |
小数被截断 |
| 14 | 文件路径对了吗?流用 try-with-resources 关了吗?编码一致吗 | FileNotFound / 乱码 |
七、我的总结
- 输入的核心是"类型匹配" :
nextInt配整数、nextDouble配小数、nextLine配整行;nextInt和nextLine混用必出问题。 - 输出的核心是"拼接 vs 格式化" :简单拼接用
+,要控制小数位数用printf。 - 方法的核心是"签名" :返回类型 + 方法名 + 参数列表,三者决定这个方法长什么样;写方法先想清楚------要不要返回值?需要什么参数?
- 报错不要慌,先看是 编译错误 (代码写法问题,改了才能跑)还是 运行时异常(跑起来才炸,多和输入、数组、空值有关)。
下一步计划:数组 + 类与对象,把方法用
static/非static的区别彻底搞懂。