Eu vou comentar algumas etapas desses códigos para te ajudar a entender um pouco.
Vou numerar os tópicos e comentar abaixo.
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class GoogleMaps {
private static final String GOOGLE_MAPS_URL = "http://maps.google.com/maps/api/geocode/json?" +
"address=%s&sensor=true_or_false"; // Tópico 1
public InputStream getJsonForAddress(String endereco) {
try {
if (endereco == null) // Tópico 2
throw new IllegalArgumentException("O endereço não deve ser nulo."); // Tópico 2
endereco = endereco.replace(" ", "+"); // Tópico 2
return new URL(
String.format(GOOGLE_MAPS_URL, endereco) // Tópico 1
).openStream(); // Tópico 3
} catch (IOException e) {
throw new RuntimeException("Não foi possível consultar o google maps para o endereço: " + endereco, e); // Tópico 4
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class InputStreamConverter {
public String convert(InputStream is) { // Tópico 3
BufferedReader reader = null;
StringBuilder sb = new StringBuilder(); // Tópico 4
String line; // Tópico 4
try {
reader = new BufferedReader(new InputStreamReader(is)); // Tópico 3
while ((line = reader.readLine()) != null) { // Tópico 4
sb.append(line); // Tópico 4
}
} catch (IOException e) {
throw new RuntimeException("Não foi possível converter o InputStream em uma String.", e); // Tópico 5
} finally { // Tópico 5
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException("Não foi possível converter o InputStream em uma String.", e);
}
}
}
return sb.toString(); // Tópico 4
}
}
As linhas comentadas fazem parte de um mesmo tópico.
Tópicos:
1 - Sobre a formatação de Strings usando o String.format. O método format é um método estático que nos retorna uma nova String formatada. O primeiro argumento é uma String que deve ser usada como padrão. O format vai procurar pelas "variáveis" nessa String.
Olhando a String GOOGLE_MAPS_URL você vai ver que no meio dela você tem um %s. Isso significa que criamos uma variável para o format colocar nesse local, e o tipo dela é String (por isso o ‘s’). Se você quisesse passar 2 Strings, precisaria usar 2 %s nos locais desejados.
Exemplo:
String.format("Olá %s, bem vindo ao programa %s", "Rafael", "Mostrando como funciona o format.");
// "Olá Rafael, bem vindo ao programa Mostrando como funciona o format."
String.format("Olá %s, bem vindo ao programa %s", "Rafael");
// "Olá Rafael, bem vindo ao programa " -> O último %s foi ignorado.
// Existem outros tipos para você concatenar usando o format:
String.format("Olá %s, bem vindo ao programa de número %d", "Rafael", 5);
// "Olá Rafael, bem vindo ao programa de número 5"
String.format("Olá %s, bem vindo ao programa de número %f", "Rafael", 5.0);
// "Olá Rafael, bem vindo ao programa de número 5.0"
String.format("Olá %s, bem vindo ao programa %b", "Rafael", true);
// "Olá Rafael, bem vindo ao programa true"
Aqui nesse link tem uma explicação mais aprofundada sobre o assunto, leia e TESTE os exemplos.
2 - Toda vez que você ver um erro de NullPointerException, a culpa será sua. O problema da NullPointerException é que ela não te diz quem está nulo, ou por quê uma determinada variável está nula.
Se nós tivéssemos omitido aquele “if” e o “throw new”, quando chamássemos o replace, ele dispararia um NullPointerException (caso o endereco seja nulo). Então, a gente SABE que não se pode buscar no google maps sem ter um endereço. Logo, se ele for nulo, nós temos um argumento ilegal no nosso método. Por isso soltamos um IllegalArgumentException. O melhor dela é que ela te fala qual é o problema, nós colocamos isso na mensagem!
Outra coisa, quando fazemos uma requisição alguns caracteres são ilegais, como o espaço e outros caracteres especiais. Por isso, fazemos o replace de espaço para o +. Pesquise melhor sobre como formatar a sua URL, pois esses caracteres especiais podem fazer com que ela não funcione e o seu InputStream volte nulo. Por isso você estava tendo uma NullPointerException, percebe como ela não te fala nada sobre o que está havendo?
3 - Assim como no tópico 2, caso o input stream seja nulo, nós temos um argumento ilegal. Primeira coisa, faça essa verificação e coloque uma mensagem adequada para que você saiba o que está acontecendo.
Você não precisa trabalhar com o InputStreamReader pois nós simplesmente criamos um quando formos ler o InputStream. Então trabalhe com InputStreams e, somente quando precisar ler, crie um Reader: new InputStreamReader(inputStream);
4 - Usamos StringBuilder aqui pois ele consegue concatenar Strings de uma forma incrivelmente rápida. Isso graças à forma como ele foi feito e graças ao método append.
Já a instrução do while pode parecer confusa e intimidante, mas ela é bem simples: while ((line = reader.readLine()) != null)
No Java, quando atribuímos um valor à uma variável, esse mesmo valor é retornado como resultado dessa expressão. Então:
int i = 2;
int j = (i = 25); // Aqui, i recebe 25 e depois j recebe 25 também.
int k = i = 2; // Aqui é igual o de cima só que sem os parêntesis.
Então temos uma variável String chamada line declarada anteriormente, depois, a cada verificação desse while, chamamos o método readLine() que retorna uma linha e colocamos dentro da variável line. Depois disso, verificamos se isso não for nulo, pois quando o método readLine() retornar nulo, quer dizer que não tem mais linhas para ele ler.
Depois, dentro do while, chamamos o método append do StringBuilder para concatenarmos essa linha nele.
No fim, mandamos o StringBuilder construir uma String com todas aquelas linhas que lemos. E, para isso, basta chamar o toString().
PS: Olhe o nome da classe "StringBuilder", ou seja, "Construtor de String".
5 - Um reader SEMPRE precisa ser fechado depois que terminamos de usar. Então, mesmo se algum erro acontecer, precisaremos fechá-lo. Por isso colocamos a instrução de close() dentro do bloco finally, que SEMPRE será executado. (mesmo se houver um return nos blocos anteriores.)
Bom, espero que essas observações ajudem, sinta-se livre para questionar e corrigir alguma besteira que eu possa ter dito.