优雅的Java ACM IO模板

对于ACM选手来说,Java I/O慢一直是个让人头疼的问题。使用Scanner输入,会比C/C++的scanf慢好几倍,并且内存开销大。

目前网上最常见的快速模板是使用BufferedReader,带缓冲按行读入测试数据,然后使用StringTokenizer将每一行分片。但这种简单做法无法预知是否读取到了流尾,有一定局限性。 也有部分实现了hasNext的模板,但一直没看到特别满意的,于是自己写了一个。

简介

Reader内部使用BufferedReadernextLine方法从输入流读取数据,由内部方法innerNextLine包装,同样使用
StringTokenizer 分片。hasNext方法会检查是否还有数据,它通过读入新数据并创建tokenizer来寻找下一个可用的token。因此,调用hasNext方法后,会确保调用tokenizer.nextToken()时可以得到数据,除非已经读取到输入流尾。nextLine方法会读入一行新数据,同时舍弃tokenizer中的内容。next方法会返回下一个数据。nextXXX方法可以将next的数据包装成常见数据类型。

Writer则是对BufferedWriter的简单包装,提供了接受Object的printprintln方法。

性能测试

测试题目: 给出未知行,每行第一个数N,随后给出N个数,求N个数之和。

测试输入1000w行,均为5 1 10 100 1000 10000,结果为11111

测试环境:
Windows10 i7-7700HQ
Java: OpenJDK 12
C++: MinGW GCC

方法执行时间峰值内存平均内存
Scanner91.2s88.7MB81.5MB
Scanner(使用缓冲输入流包装)106.9s96.2MB81.5MB
Java快速IO模板9.8s84.1MB79.1MB
cin / cout107.5s0.4MB0.4MB
scanf / printf10.1s0.4MB0.4MB
C / C++输入输出挂2.4s0.4MB0.4MB

模板

import java.io.*;
import java.math.BigInteger;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        AReader reader = new AReader(System.in);
        AWriter writer = new AWriter(System.out);

        // Do something

        reader.close();
        writer.close();
    }
}

// Fast reader for ACM By Azure99
class AReader implements Closeable {
    private BufferedReader reader;
    private StringTokenizer tokenizer;

    public AReader(InputStream inputStream) {
        reader = new BufferedReader(new InputStreamReader(inputStream));
        tokenizer = new StringTokenizer("");
    }

    private String innerNextLine() {
        try {
            return reader.readLine();
        } catch (IOException ex) {
            return null;
        }
    }

    public boolean hasNext() {
        while (!tokenizer.hasMoreTokens()) {
            String nextLine = innerNextLine();
            if (nextLine == null) {
                return false;
            }

            tokenizer = new StringTokenizer(nextLine);
        }

        return true;
    }

    public String nextLine() {
        tokenizer = new StringTokenizer("");
        return innerNextLine();
    }

    public String next() {
        hasNext();
        return tokenizer.nextToken();
    }

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

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

    public BigInteger nextBigInteger() {
        return new BigInteger(next());
    }

    @Override
    public void close() throws IOException {
        reader.close();
    }
}

// Fast writer for ACM By Azure99
class AWriter implements Closeable {
    private BufferedWriter writer;

    public AWriter(OutputStream outputStream) {
        writer = new BufferedWriter(new OutputStreamWriter(outputStream));
    }

    public void print(Object object) throws IOException {
        writer.write(object.toString());
    }

    public void println(Object object) throws IOException {
        writer.write(object.toString());
        writer.write("\n");
    }

    @Override
    public void close() throws IOException {
        writer.close();
    }
}

Azure99

大二蒟蒻,喜欢折腾vps、玩机,偶尔写写代码

You may also like...

发表评论

电子邮件地址不会被公开。 必填项已用*标注