43

I want to type a multiple line text into the console using a BufferedReader and when I hit "Enter" to find the sum of the length of the whole text. The problem is that it seems I'm getting into an infinite loop and when I press "Enter" the program does not come to an end. My code is below:

InputStreamReader instream = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(instream);

    line= buffer.readLine();

    while (line!=null){
        length = length + line.length();
        line= buffer.readLine();
    }

Could you please tell me what I'm doing wrong?

dbank
  • 1,173
  • 1
  • 17
  • 29
deadpixels
  • 769
  • 1
  • 12
  • 21
  • 5
    when you only press enter `line` will equal "" not null. try changing `line != null` to `!line.equals("")` – Stephen Buttolph Mar 11 '15 at 02:01
  • 3
    Also, just to provide some other opinions (e.g. using a for loop), http://codereview.stackexchange.com/questions/44135/is-it-ok-to-use-while-line-r-readline-null-construct – Foon Mar 11 '15 at 02:23
  • I realized last night as I was falling asleep: what are you using length for? NB that if you were to do cat myfile | java yourprogram and print out the value of length, this will disagree with what, e.g. wc prints out, because you're not counting newlines. If you need to do that, note that DOS files will have "\r\n" and UNIX files will have "\n" and my original suggestion to use System.getProperty("line.separator") probably won't work because there's no guarantee that you aren't e.g. trying to read a DOS file under Linux. (So, hopefully that's not what you're mean to do) – Foon Mar 11 '15 at 11:58

8 Answers8

107

One line of code using Java 8:

line =  buffer.lines().collect(Collectors.joining());
Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
Russel Yang
  • 2,633
  • 3
  • 21
  • 18
  • 9
    Do I need to include a newline as a delimiter to preserve lines? – Brett Y Aug 30 '19 at 14:23
  • 4
    Yes, you have to add a possible separator to preserve lines: `buffer.lines() .collect(Collectors.joining(System.lineSeparator()));` – Wumba Mar 08 '21 at 15:23
40

The idiomatic way to read all of the lines is while ((line = buffer.readLine()) != null). Also, I would suggest a try-with-resources statement. Something like

try (InputStreamReader instream = new InputStreamReader(System.in);
        BufferedReader buffer = new BufferedReader(instream)) {
    long length = 0;
    String line;
    while ((line = buffer.readLine()) != null) {
        length += line.length();
    }
    System.out.println("Read length: " + length);
} catch (Exception e) {
    e.printStackTrace();
}

If you want to end the loop when you receive an empty line, add a test for that in the while loop

while ((line = buffer.readLine()) != null) {
    if (line.isEmpty()) {
        break;
    }
    length += line.length();
}

JLS-14.15. The break Statement says

A break statement transfers control out of an enclosing statement.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
5

line will not be null when you press enter; it will be an empty string.

Take note of what the BufferedReader JavaDoc says about readLine():

Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.

And readLine() returns:

A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached

So when you press [Enter], you are giving the BufferedReader a new line containing only \n, \r, or \r\n. This means that readLine() will return an empty string.

So try something like this instead:

InputStreamReader instream = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(instream);

line = buffer.readLine();

while( (line != null) && (!line.isEmpty()) ){
    length = length + line.length();
    line = buffer.readLine();
}
dbank
  • 1,173
  • 1
  • 17
  • 29
  • 2
    I may be wrong. But I don't think the returned String actually contains the end line character. If it did then a `System.out.println(buffer.readLine());` would have another line at the end right? – Stephen Buttolph Mar 11 '15 at 02:48
  • 2
    Also in the JavaDoc you linked to: *"returns [...] the contents of the line, not including any line-termination characters"*. – Radiodef Mar 11 '15 at 02:49
  • @StephenB and @RadioDef: Ah my mistake! You are both right. I was confused with `read()` and who knows what. – dbank Mar 11 '15 at 02:58
  • 1
    `while(!line.isEmpty()) {...}` like you had before you deleted was correct... (Besides the fact that some have also pointed out that `readLine` can still return null if the user does something obscure.) – Radiodef Mar 11 '15 at 03:01
  • 1
    I edited to correct my answer. @StephenB and RadioDef, thank you both for calling me out and correcting me so that I didn't spread misinformation. – dbank Mar 11 '15 at 03:07
4

When you only press Enter the return from buffer.readLine(); isn't null it is an empty String.

Therefore you should change line != null to !line.equals("") (You could also change it to line.length() > 0)

Now your code will look something like this:

InputStreamReader instream = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(instream);

line = buffer.readLine();

while (!line.equals("")){
    length = length + line.length();
    line = buffer.readLine();
}

This should solve your problem. Hope this helped! :)

Stephen Buttolph
  • 643
  • 8
  • 16
2

Since Java 8 you can use BufferedReader#lines method directly on buffered reader.

    try (InputStreamReader in = new InputStreamReader(System.in);
         BufferedReader buffer = new BufferedReader(in)) {
        final int length = buffer.lines().mapToInt(String::length).sum();
        System.out.println("Read length: " + length);
    } catch (Exception e) {
        e.printStackTrace();
    }
JuanMoreno
  • 2,498
  • 1
  • 25
  • 34
Grzegorz Gajos
  • 2,253
  • 19
  • 26
0

Snarky answer: what you're doing wrong is only creating 2 objects in Java to do something... if you search, you can probably find a few more classes that extend BufferedReader or ExtendedBufferReader etc., and then it can be real Enterprise Java.

Now that i've gotten that out of my system: more useful answer. System.in is closed when you input EOF, which is Control-D under Linux and I think MacOS, and I think Control-Z plus enter under Windows. If you want to check for enter (or more specifically, two enters... one to finish the last line and one to indicate that you're done, which is essentially how http handles determining when the http headers are finished and it's time for the http body, then @dbank 's solution should be a viable option with a minor fix I'm going to try to make to move the ! inside the while predicate instead of !while.

(Edit #2: realized readLine strips the newline, so an empty line would "" instead of the newline, so now my code devolves to another answer with the EOF bit as an answer instead of comment)

Edit... that's weird, @dbank had answered while I was typing my answer, and I would have stopped had I not though mentioning the EOF alternative. To repeat his code from memory with the edit I was going to make:

InputStreamReader instream = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(instream);

    line= buffer.readLine();
    while (line != null && !line.equals("")){
        length = length + line.length();
        line= buffer.readLine();
    }
Foon
  • 6,148
  • 11
  • 40
  • 42
  • To the down voter(s): if this was because of the snarky answer at the top, byte me (I mean, new Byte []("me".getBytes(Charset.forName("UTF-8"))). Otherwise, I'm curious why the downvotes: My code is similar to others (and when I posted @dbank's answer appeared, disappered, and now reappearered; you can't see it now at the 9 hour mark, but my answer was posted marginally before the others) and I also mention the EOF option (which is also useful when piping) – Foon Mar 11 '15 at 11:54
0

Put every lines into String[] array. and second method get the number of lines contains in text file. I hope this might be useful to anyone..

public static void main(String... args) throws IOException {
    String[] data = getLines();
    for(String v : data) {
        out.println(v);
    }
}

public static String[] getLines() throws IOException {
    BufferedReader bufferReader = new BufferedReader(new FileReader("C:\\testing.txt"));
    String line = bufferReader.readLine(); 
    String[] data = new String[getLinesLength()];
    int i = 0;
    while(line != null) {
        data[i] = line; 
        line = bufferReader.readLine();
        i++;
    }
    bufferReader.close();
    return data;
}

public static int getLinesLength() throws IOException {
    BufferedReader bufferReader = new BufferedReader(new FileReader("C:\\testing.txt"));
    String line = bufferReader.readLine(); 
    int size = 0;
    while(line != null) {
        size += 1;
        line = bufferReader.readLine();
    }
    bufferReader.close();
    return size;
}
Snowbases
  • 2,316
  • 2
  • 20
  • 26
0

Good example from @Russel Yang (https://stackoverflow.com/a/40412945/11079418).

Use this code, to add also a new line character after each line.

String lines = bufferedReader.lines().map(line -> line + "\n").collect(Collectors.joining());
StackOverflow
  • 116
  • 1
  • 6