目前有一个Android应用程序的问题,我认为该线程正在尝试使用对象,然后才能正确实例化。
这是我班级的构造函数:
String name;
String price;
String percentChange;
String peRatio;
private String ticker;
private JSONObject stockQuote;
public Stock(String ticker) {
this.ticker = ticker;
// Build query and URL.
String url = "http://query.yahooapis.com/v1/public/yql?q=";
String query = "select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(\"" +
ticker +
"\")&env=store://datatables.org/alltableswithkeys&format=json";
url += query;
stockQuote = fetch(url);
name = get("symbol");
price = get("Ask");
}
这里的fetch()函数用于从HTTP响应中检索JSONObject:
private JSONObject fetch(String myurl) throws IOException {
InputStream is = null;
String contentAsString = "";
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
is = conn.getInputStream();
// Convert the InputStream into a string
contentAsString = readIt(is);
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
JSONObject queryResult = null;
try {
JSONObject json = new JSONObject(contentAsString);
queryResult = json.getJSONObject("query").getJSONObject("results").getJSONObject("quote");
} catch (JSONException e) {
System.err.println("Failed to decode JSON");
}
return queryResult;
}
最后是get()方法,用于从JSONObject中检索字符串:
public String get(String key) {
String value = null;
try {
value = stockQuote.getString(key);
} catch (JSONException e) {
System.err.println("Couldn't find " + key);
}
return value;
}
NullPointerException被" value = stockQuote.getString(key)抛出;" - 有时,但不是每次。我认为这是因为它在解析HTML响应之前尝试访问stockQuote?
我猜这是一个明显的解决方案,但我以前没遇到过这个问题。有什么想法吗?
答案 0 :(得分:2)
我怀疑这里的主要问题是可见性,正如@shmosel在上面的评论中所说的那样:因为stockQuote
是非最终的,所以一旦确定了所有线程,就不能保证所分配的值可见。构造函数完成。制作stockQuote
final应该可以解决这个问题。
我是否可以建议在构造函数中完成这样的工作是一个坏主意:它使测试变得困难(Miško Hevery关于这篇文章的文章是一个很好的阅读),而你正在调用外星人构造函数中的方法,不鼓励(例如,通过Java Concurrency In Practice)。
相反,您可以将作品(下载代码)移动到静态工厂方法中,这样可以更好地修复竞争条件:
public static Stock create(String ticker) {
// Build query and URL.
String url = "http://query.yahooapis.com/v1/public/yql?q=";
String query = "select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(\"" +
ticker +
"\")&env=store://datatables.org/alltableswithkeys&format=json";
url += query;
JSONObject stockQuote = fetch(url);
return new Stock(ticker, stockQuote);
}
private Stock(String ticker, JSONObject stockQuote) {
this.ticker = ticker;
this.stockQuote = stockQuote;
if (stockQuote == null) throw new NullPointerException();
name = get("symbol");
price = get("Ask");
}
通过这种方式,您可以在Stock
可用之前拥有stockQuote
的实例,因此在致电NullPointerException
时无法获得get
。 (get
也应该final
,因此它也不是外来方法。
(当然,如果您需要继承Stock
,这不会那么容易。)
您还可以更轻松地测试Stock
课程,因为您可以直接注入JSONObject
,而不必下载"真实"一个(如果你使构造函数非私有)。