我几天来一直在讨论这个问题。我已经完成了谷歌的全部分享,我希望我能在这里找到一个比我更有经验的人(不难发现哈哈),这可以解读我的问题。
场景:我开发了一个实现Swing GUI的Java Applet。后台工作:Applet从大型“电话簿”excel文件(.csv)中收集记录,并将它们存储在Map数据结构中。电话簿包含大约106,000条记录,在第34,586条记录中,我得到一个我无法理解的ArrayIndexOutOfBoundsException。 只有当我在个人网站上运行小程序时才会出现异常。在我的IDE(NetBeans)中测试并在我的本地计算机上运行.html文件(包含applet的文件)时,applet运行完美,没有错误。在我的网站上运行时抛出的输出和异常如下(我剪切了大部分记录以节省空间):
Java控制台
Kary,Webber,2826 East 12th Ave.,Memphis,TN,38168,901-749-1834
Erinn,Rocha,2132 East Main Ave.,Memphis,TN,38168,865-414-5105
Gina,Lane,71 South First St. Apt. 11,Memphis,TN,38168,731-485-1129
Patsy,Hart,661 East 11th St.
java.lang.ArrayIndexOutOfBoundsException: 3
at Implementation.PersonnelDatabase.addRecordFromFields(PersonnelDatabase.java:192)
at Implementation.PersonnelDatabase.initDBFromFile(PersonnelDatabase.java:215)
at Implementation.PersonnelDatabase.processData(PersonnelDatabase.java:239)
at Implementation.PersonnelDatabaseApplet$2.doInBackground(PersonnelDatabaseApplet.java:78)
at Implementation.PersonnelDatabaseApplet$2.doInBackground(PersonnelDatabaseApplet.java:69)
at javax.swing.SwingWorker$1.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at javax.swing.SwingWorker.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
正如你所看到的,在第34,586条记录中(从Patsy,Hart开始),它在她的地址中间输出。完整记录如下:Patsy,Hart,661 East 11th St. Apt。 195,孟菲斯,田纳西州,38168,555-555-5555。
以下是最受逻辑影响的代码部分。
HTML文件中的对象标记
<object type="application/x-java-applet" height="400" width="300">
<param name="codebase" value="classes" />
<param name="code" value="Implementation/PersonnelDatabaseApplet.class" />
<param name="archive" value="PersonnelDatabase.jar" />
Applet failed to run. No Java plug-in was found.
</object>
PersonnelDatabase类(处理背景数据):
/*
* Create a new record using an appropriately ordered set of fields and add it to the data base
*/
public void addRecordFromFields(String[] fields)
{
// Read record attributes in, one at a time
Record thisRecord = new Record();
thisRecord.setFirstName(fields[0]);
thisRecord.setLastName(fields[1]);
thisRecord.setAddress(fields[2]);
thisRecord.setCity(fields[3]);
thisRecord.setState(fields[4]);
thisRecord.setZipCode(fields[5]);
thisRecord.setPhoneNo(fields[6]);
addRecord(thisRecord);
}
// O( n )
/**
* Destroy the current data base and load new data from a file.
* @param filename the file to use as a source
* @throws IOException: Either file not found or IO error
*/
public void initDBFromFile(URL url) throws IOException
{
// Open and read the file
InputStream in = url.openStream();
BufferedReader filein = new BufferedReader(new InputStreamReader(in));
// Read record file, parse lines, and add records to data base
String line = filein.readLine();
while(line != null) {
System.err.println(line);
String[] fields = line.split(",");
addRecordFromFields(fields);
line = filein.readLine();
}
filein.close();
}
/**
* Loads the default library and provides for interaction with the data
* via the JPanel GUI inputs.
* @param args
* @throws IOException
*/
public String processData(String input, int selection, URL url)
{
//Create the main library object
PersonnelDatabase dbiLib = new PersonnelDatabase();
System.err.println(url);
// Try to read the default library
try
{
dbiLib.initDBFromFile(url);
}
catch (IOException e)
{
System.err.println("File IO Error");
e.printStackTrace();
System.exit(1);
}
// Queries can be simulated by typing into the console in Eclipse, and using Ctrl-d (Ctrl-z in Windows) when finished.
// For example: "searchLastName,Smith" would print a list of all people with the last name of Smith.
Iterable<Record> result = null;
String[] fields = new String[2];
if (input.contains(",")) {
fields = input.split(",");
}
switch(selection) {
case 0: result = dbiLib.searchByFirstName(input); break;
case 1: result = dbiLib.searchByLastName(input); break;
case 2: result = dbiLib.searchByFullName(fields[0].trim(), fields[1].trim()); break;
case 3: result = dbiLib.searchByCity(input); break;
case 4: result = dbiLib.searchByState(input); break;
case 5: result = dbiLib.searchByCityState(fields[0].trim(), fields[1].trim()); break;
case 6: result = dbiLib.searchByZip(input); break;
case 7: result = dbiLib.searchByPhoneNumber(input); break;
case 8: String[] newFields = new String[fields.length-1];
System.arraycopy(fields, 1, newFields, 0, fields.length-1);
dbiLib.addRecordFromFields(newFields);
return "Record added successfully!\nEnter a query or add another record.";
default: return "Invalid query.\nEnter another query or add a record.";
}
PersonnelDatabaseApplet类(初始化GUI,收集输入并显示输出):
public void init() {
/* Create and display the applet */
try {
java.awt.EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
initComponents();
}
});
} catch (Exception e) {
System.err.println("Creation of GUI did not successfully complete.");
}
}
// Process inputs in the background.
SwingWorker worker = new SwingWorker<String, Void>() {
@Override
public String doInBackground() {
URL url = null;
try {
url = new URL(getCodeBase(), fileToRead);
}
catch(MalformedURLException e){}
personnelDatabase = new PersonnelDatabase();
final String output = personnelDatabase.processData(input, selection, url);
return output;
}
@Override
public void done() {
processingLabel.setVisible(true);
try {
textToDisplay = get(15, TimeUnit.SECONDS);
} catch (InterruptedException ignore) {
ignore.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if(cause != null) {
why = cause.getMessage();
cause.printStackTrace();
} else {
why = e.getMessage();
e.printStackTrace();
}
System.err.println("Error retrieving request: " + why);
}
if(worker.isDone() && textToDisplay != null) {
processingLabel.setVisible(false);
outputTextArea.setText(textToDisplay);
}
}
};
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {
selection = searchComboBox.getSelectedIndex();
input = valueTextField.getText();
processingLabel.setVisible(true);
worker.execute();
}
在我的个人网站上链接到Applet: http://www.ryan-taylor.me/Applied%20Maps/build/PersonnelDatabaseApplet.html
我很确定这个错误与excel数据本身无关,因为这个程序在NetBeans中运行得很好,并且在我的本地机器上运行html时。我猜它与Swing(线程)有关,但我不确定。我通过使用SwingWorker进行了更改以帮助在Swing线程之间传输数据,但我没有运气。我想在实施它时总是有可能错过了一些东西。
我还考虑过签署jar,但我正在处理的文件是在线存储的 - 而不是本地机器 - 所以我没有看到真正的需求。
如果有人有任何建议,我将不胜感激!
答案 0 :(得分:3)
看起来超出范围的数组索引是3
,因为输入行只包含三个字段,而您尝试访问第四个字段(索引3),而不检查它是否确实存在。
thisRecord.setCity(fields[3]);
因为数组fields
只有三个元素。在
String[] fields = line.split(",");
addRecordFromFields(fields);
当你到达 p>
Patsy,Hart,661 East 11th St.
只使用3个条目创建数组fields
。
如果预期字段数不变,则应拒绝没有正确数量字段的输入行。如果字段数可能不同,则必须检查返回的实际数字,并仅提取实际存在的元素。
答案 1 :(得分:2)
在浏览器中运行applet时,看起来有些东西会导致文件被截断。我的猜测是你从Web服务器获取文件,服务器或浏览器默默地执行一些下载限制。 (或者,当您上传文件时,文件可能会被截断...)
答案 2 :(得分:1)
我怀疑您的worker
与网络延迟暴露的另一个线程之间存在数据竞争。有两件事可能会受到更严格的审查:
只要不对initial thread进行进一步处理,使用invokeAndWait()
初始化GUI是合理的。
worker
对于publish()
的{{1}}非常不寻常,因为example可以作为事件发送线程process()
记录的一种方式。