Java:结合使用BufferedReader和PrintWriter会导致问题

Java:结合使用BufferedReader和PrintWriter会导致问题,java,io,Java,Io,我试图通过实验和《Java2:完整参考》一书第五版了解Java的io包。。下面,我尝试制作一个非常简单的程序,使用BufferedReader实例获取一些输入,并使用PrintWriter实例提供一些简单的控制台输出 package io; import java.io.*; public class UsingPrinterWriter { public static void main(String argv[]) { PrintWriter output = n

我试图通过实验和《Java2:完整参考》一书第五版了解Java的io包。。下面,我尝试制作一个非常简单的程序,使用BufferedReader实例获取一些输入,并使用PrintWriter实例提供一些简单的控制台输出

package io;

import java.io.*;

public class UsingPrinterWriter {
    public static void main(String argv[]) {
        PrintWriter output = new PrintWriter(System.out, true);
        Profile hypro = Profile.promptedProfile();
        output.print(hypro);
        output.close();
        return;
    }
}

class Profile {
    private String first_name;
    private String last_name;
    private int age;

    Profile() {}

    Profile(String first_name, String last_name, int age) {
        this.first_name = first_name;
        this.last_name = last_name;
        this.age = age;
    }

    void setFirstName(String fn) {
        this.first_name = fn;
        return;
    }

    void setLastName(String ln) {
        this.last_name = ln;
        return;
    }

    void setAge(int a) {
        this.age = a;
        return;
    }

    static Profile promptedProfile() {
        Profile new_profile = new Profile();

        // create the writer and reader
        PrintWriter output = new PrintWriter(System.out, true);
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

        try {
            // prompt for first name
            output.print("Enter your first name: ");
            new_profile.setFirstName(input.readLine());

            // prompt for last name
            output.print("Enter your last name: ");
            new_profile.setLastName(input.readLine());

            // prompt for age
            output.print("Enter your age: ");
            while(true) {
                try {
                    new_profile.setAge(Integer.parseInt(input.readLine()));
                    if(new_profile.age > 0 && new_profile.age < 110) {
                        break;
                    }
                    throw new NumberFormatException("Out of bounds.");
                } catch(NumberFormatException nfe) {
                    output.print("Invalid response, try again: ");
                }
            }
            input.close();          
        } catch (IOException ioe) {
            output.println(ioe);
        } finally {
            output.close();
        }

        return new_profile;
    }

    @Override
    public String toString() {
        return String.format("Profile:\n  Name: %s %s\n  Age: %d\n", this.first_name, this.last_name, this.age);
    }
}
问题2: 行:output.printhypro;不会被打印出来。行Profile hypro=Profile.promptedProfile;之后的任何内容

所以我想问:

关于这些io类的概念性知识,我似乎遗漏了,这是怎么回事? 如何解决这些问题? 提前,谢谢

另外,我已经知道java.util.Scanner类,但我想在不使用它的情况下解决这个问题。此外,我愿意接受关于我应该在这里实现的任何更好的编程实践的建议。

PrintWriter是缓冲的,并且在以下情况之一之前不会刷新自身:

你叫同花顺,还是 您为autoflush参数构造了true,并通过调用println或在传递给print或write的数据中\n或\r\n打印了一个行终止符。 你没有做这些事情。如果要在打印后立即显示行终止输出,则需要刷新

不要对setter使用return语句。 您只能打开一个PrintWriter并将其传递给promptedProfile方法 使用PrintWriter的printlnString str方法打印到控制台 完成所有操作后,关闭PrintWriter。 使用适当的java变量约定 尝试下面的代码并了解自己。
让我们从一些基本知识开始:

首先,刷新流意味着什么?好吧,它只是意味着当您刷新缓冲流时,它的所有数据都被清除并发送到目标目的地。在代码中,刷新输出将确保其中的所有数据都发送到console System.out进行打印

其次,stream System.out是一个静态流,也就是说,您只能获得该流的一个副本,关闭它后,您不能再次使用它来打印内容

问题1:现在,尽管已启用自动刷新PrintWriter output=new PrintWriterSystem.out,但为true;//第二个参数为true,仅当遇到回车换行符、CRLF或a时\r\n才会调用自动刷新,并且由于输出语句缺少这些字符,因此不会打印任何提示,因为未在正确的时间刷新流。数据一直附加到流,直到程序结束时,自动刷新最终第一次和最后一次运行,因此,当程序终止时,所有语句都打印在一行中

修复方法:如前一个答案中所述,您可以使用println而不是print,也可以将缺少的字符添加到print调用中,如下所示:

output.printnew\u profile.getName+\r\n


或者,您可以在@EJP建议的每次打印调用编辑之后手动调用flush,如果您希望在创建多个输出的同一行中获得输出,那么您需要零,因为您应该使用System.out。当代码中充满了不必要的东西时,很难遵循它。基本上,您的问题可能源于创建这些包装器,它们都共享您应该使用的System.in和out。您可以创建一个BufferedReader来读取输入,但不需要为输出做任何事情。“只创建一个并共享它”。@Kayaman,在书中,Herbert Schildt说:在学习Java或调试程序时,使用System.out将简单的文本输出写入控制台并没有错。但是,使用PrintWriter将使您的实际应用程序更易于国际化。因为它是字符流而不是字节流。这就是为什么我坚持使用看似不必要的PrintWriter实例。我以前曾直接将BufferedReader与System.out结合使用,没有遇到任何问题。但这不是我在这里要做的。好吧,现实世界的应用程序不再真正打印到控制台上,所以这本书的时代正在显现。尽管如此,我相信这本书并没有说在任何地方都要创造一个新的版画作家。你可以进进出出,但如果你这样做了,就做一次。这本书可能也不适合你,它似乎是一个快速参考。@Kayaman是的,这本书提到现实世界的应用程序不再真正打印到控制台上,你是对的,我想它更像是一个快速参考。无论如何,我意识到了我的错误:当我们将输入或输出流链接起来,即将它们彼此缠绕在一起时,关闭外部流也会自动关闭内部流。无论如何,我想这就是我在第二期中需要知道的。你实际上没有在这里解释任何东西,OP确实要求“概念性知识”:你的一些建议被取消了。关闭PrintWriter也会关闭System.out,这在中是不可取的
全体的OP可能不希望他的提示以行结束输出。您的编辑都是徒劳的。他们所做的只是在不需要时添加一个额外的线路终止符和两个调用刷新。这里仍然没有解释。OP可能不希望他的提示以行结束输出。还有另一个解决方案。@EJP好吧,我在写答案的时候脑子里想的都是同花顺电话,不知道我怎么忘了,所以我不知道你是否在谈论另一个解决方案,如果你能告诉我们,我会很高兴的
first
last
20
Enter your first name: Enter your last name: Enter your age:
import java.io.*;

public class UsingPrinterWriter {
    public static void main(String argv[]) {
        PrintWriter output = new PrintWriter(System.out, true);
        Profile hypro = Profile.promptedProfile(output);
        output.print("\n");
        output.flush();
        output.println(hypro);
        output.close();
    }
}

class Profile {
private String firstName;
private String lastName;
private int age;

Profile() {
}

Profile(String firstName, String lastName, int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
}

void setFirstName(String fn) {
    this.firstName = fn;

}

void setLastName(String ln) {
    this.firstName = ln;
}

void setAge(int a) {
    this.age = a;
}

static Profile promptedProfile(PrintWriter output) {
    Profile newProfile = new Profile();
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

    try {
        // prompt for first name
        output.println("Enter your first name: ");
        output.flush();
        newProfile.setFirstName(input.readLine());

        // prompt for last name
        output.println("Enter your last name: ");
        output.flush();
        newProfile.setLastName(input.readLine());

        // prompt for age
        output.println("Enter your age: ");
        output.flush();
        while (true) {
            try {
                newProfile.setAge(Integer.parseInt(input.readLine()));
                if (newProfile.age > 0 && newProfile.age < 110) {
                    break;
                }
                throw new NumberFormatException("Out of bounds.");
            } catch (NumberFormatException nfe) {
                output.println("Invalid response, try again: ");
            }
        }
        input.close();
    } catch (IOException ioe) {
        output.println(ioe);
    }

    return newProfile;
}

@Override
public String toString() {
    return String.format("Profile:\n  Name: %s %s\n  Age: %d\n", this.firstName, this.lastName, this.age);
}
}