在算法竞赛或大规模数据处理场景中,Java的Scanner类虽然使用方便,但其性能表现常常成为程序的瓶颈。尤其是在读取大量输入时,Scanner的效率远低于基于缓冲的输入方式。今天,我想分享一个我在多次竞赛中打磨出的高效输入输出模板,它能让你在不改变编码习惯的前提下,大幅提升输入速度。

为什么需要这个模板?

在Codeforces、蓝桥杯等竞赛平台中,当输入数据量较大(如10^6级别以上)时,使用Scanner很容易因为超时而失败。而BufferedReader配合StringTokenizer可以将输入速度提升数倍甚至十倍以上。

但直接使用BufferedReader读取字符串再解析,代码变得繁琐。于是,我设计了一个封装类 MyScanner,它兼容Scanner,可以实现从Scanner到高性能输入的无感切换


我的竞赛模板代码

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        MyScanner sc = new MyScanner();
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        //code here

        
        out.flush(); // ⚠️ 关键!必须调用flush()
    }
}

class MyScanner {
    private BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    private StringTokenizer st;

    public String nextLine() {
        try {
            return br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String next() {
        //注意这里要使用while
        while (st == null || !st.hasMoreTokens()) {
            st = new StringTokenizer(nextLine());
        }
        return st.nextToken();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    public long nextLong() {
        return Long.parseLong(next());
    }

    public double nextDouble() {
        return Double.parseDouble(next());
    }
}

模板的核心优势

✅ 1. 无感切换,零学习成本

你原来怎么用Scanner,现在就怎么用MyScanner

// 原来
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();

// 现在
MyScanner sc = new MyScanner();
int a = sc.nextInt(); // 用法完全一样!

无需修改任何业务逻辑代码,只需替换声明部分,即可享受性能飞跃。

✅ 2. 极致性能优化

  • 使用 BufferedReader 进行整行读取,减少I/O调用次数。

  • 使用 StringTokenizer 高效分割字符串,比split()更快。

  • 输出使用 PrintWriter + BufferedWriter 组合,批量写入,减少系统调用。

在处理10万级别输入时,速度通常是Scanner5~10倍


⚠️ 重要提醒:别忘了 out.flush()

使用缓冲输出时,数据并不会立即写入控制台或输出文件,而是先存入缓冲区。如果你忘记调用 out.flush(),可能导致输出内容不完整甚至完全丢失!

务必在 main 函数的最后,在输出全部完成后调用:

out.flush();

使用建议

  1. 竞赛必备:每次打比赛前,先把这套模板复制到你的代码框架中。

  2. 命名规范:建议类名保持为 Main,以兼容大多数OJ平台。

  3. 扩展性:你可以根据需要为 MyScanner 添加 nextChar()nextBoolean() 等方法。


总结

这个模板是我经过多次竞赛实战验证的“生产力工具”。它既保留了Scanner的易用性,又拥有了BufferedReader的高性能。无感升级 + 高效稳定 + 易于维护,非常适合算法竞赛、笔试、机试等对性能敏感的场景。

希望这个模板也能帮你避开“输入超时”的坑,写出更快、更稳的Java代码!

如果你有类似的优化技巧,欢迎在评论区分享交流!