In short, think of an InputStream like a conveyor belt of raw materials:
The InputStreamReader is a machine that translates those raw materials into parts (characters).
The BufferedReader is a storage area that batches parts for efficiency.
The Stream and Collectors.joining() assemble the parts into the final product (a String).
This is how Java processes streams behind the scenes to give you a String!
Here is an example of how we can do it:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
public String convertStreamToString(InputStream is) {
if (is == null) return "";
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
} catch (Exception e) {
e.printStackTrace();
return "";
}
}