The IO streams are bytes based, they have no concept of characters or strings which in Java program we need to deal with. That is what readers come in.
A byte can be anything, it can be a character, a number, a boolean value, a color, etc. It depend how the program interpret it. Streams and readers just works on a different level of abstraction.
BufferedReader, as its name indicated , can buffering an input stream and improve the read performance.
Construct BufferedReader instance
There are two ways to construct a BufferedReader:
With the first form, buffer size is default which can handle most cases, the second form let you customize the buffer size, if the default size is not enough.
The usual way to use is to construct BufferedReader with an InputStreamReader:
Another example: read from URL stream
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
You can even buffer the read from String
String source; BufferedReader br = new BufferedReader( new InputStreamReader(new ByteArrayInputStream(source.getBytes()), stream.encoding) );
Why we need BufferedReader?
The key factor is performance, generally, BufferedReader with larger buffer size > BufferedReader with smaller buffer size > Stream IO with no buffer.
So the common way to tune performance is first use BufferedReader instead of Stream IO, then increase the buffer size when needed.
It's just simple math, you have 10 lines to read, you can either read one line each time for 10 times, or read 5 lines a time for 2 times. The second approach will be faster.