MGordon0405 MGordon0405 - 3 months ago 25
Java Question

Java - Understanding PrintWriter and need for flush

Ok, firstly I apologise for all the code but I feel like too much code is better than not enough. I'm making a simple chat client and printwriter in particular i'm struggling with. With the code the way it is the now it will interact with the server class and perfectly fine and print what im wanting to print. However, when I remove 'writer.flush();' it will stop printing. With my understanding -which is evidently wrong- 'writer.println(outgoing.getText());' should be enough as this would send the text im trying to send to the server. I understand flush forces all the information to write but why is this required when i've already written what I want to write?

public class SimpleChatClientA {

JTextArea incoming;
JTextField outgoing;
BufferedReader reader;
PrintWriter writer;
Socket sock;

public void go(){

JFrame frame = new JFrame("Ludicrously Simple Chat Client");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();

incoming = new JTextArea(15,50);
incoming.setLineWrap(true);
incoming.setWrapStyleWord(true);
incoming.setEditable(false);

JScrollPane qScroller = new JScrollPane(incoming);
qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

outgoing = new JTextField(20);

JButton sendButton = new JButton("Send");
sendButton.addActionListener(new SendButtonListener());

mainPanel.add(qScroller);
mainPanel.add(outgoing);
mainPanel.add(sendButton);
setUpNetworking();

Thread readerThread = new Thread(new IncomingReader());
readerThread.start();

frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
frame.setSize(400, 500);
frame.setVisible(true);


}//close go

public void setUpNetworking(){
try{

sock = new Socket("127.0.0.1", 5000);

InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());

reader = new BufferedReader(streamReader);
writer = new PrintWriter(sock.getOutputStream());
System.out.println("network established");
}catch(Exception e){
e.printStackTrace();
}
}//close setupnetworking

public class SendButtonListener implements ActionListener{

@Override
public void actionPerformed(ActionEvent e) {

try{
writer.println(outgoing.getText());
writer.flush();
}catch(Exception ex){
ex.printStackTrace();
}
outgoing.setText("");
outgoing.requestFocus();
}

}//close sendbuttonlistener inner class


public class IncomingReader implements Runnable{

public void run(){
String message;
try{

while((message = reader.readLine()) != null){
System.out.println("read " + message);
incoming.append(message + "\n");
}

}catch(Exception e){
e.printStackTrace();
}
}

}//close inner class incomingreader


public static void main(String[] args){
new SimpleChatClientA().go();
}


}

Thanks in advance, if there is anymore information I can give please let me know first time i've properly posted to stackoverflow.

Answer

It's more efficient not to flush the data after every single println. If you're writing a lot of data, you want to buffer it and send in big chunks, not send each line separately. That's why you need to manually flush the streams if you want to make sure that the data is indeed sent to the other end.

Imagine you're writing an email to a friend, and you send each word as its own email vs. sending the whole text in a single email. Which do you think is faster? Sure, your friend will get to read the mail quicker if you send each word as you think of it, but the total time taken will become longer.