我在java GUI应用程序中编写了一个递归搜索方法来查找驱动器中的文件。
UI 响应良好,搜索成功,但
JList
未填充,而控制台成功打印文件名,点击 3 次搜索按钮后,文件将添加到 JList
中,但每个文件的名称重复
//nullpointerexception
java.util.concurrent.ExecutionException:
java.lang.NullPointerException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at javax.swing.SwingWorker.get(SwingWorker.java:602)
at searchapp.searchScreen$4.propertyChange(searchScreen.java:90)
at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335)
atjava.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport.firePropertyChange(SwingWorker.java:854)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport$1.run(SwingWorker.java:859)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:312)
at javax.swing.Timer$DoPostEvent.run(Timer.java:244)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:738)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:699)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:708)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Caused by: java.lang.NullPointerException
at searchapp.searchWorker.search(searchWorker.java:65)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.doInBackground(searchWorker.java:51)
at searchapp.searchWorker.doInBackground(searchWorker.java:21)
at javax.swing.SwingWorker$1.call(SwingWorker.java:296)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at javax.swing.SwingWorker.run(SwingWorker.java:335)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at javax.swing.SwingWorker.get(SwingWorker.java:602)
at searchapp.searchScreen$4.propertyChange(searchScreen.java:90)
at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335)
at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport.firePropertyChange(SwingWorker.java:854)
at javax.swing.SwingWorker$SwingWorkerPropertyChangeSupport$1.run(SwingWorker.java:859)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
at javax.swing.Timer.fireActionPerformed(Timer.java:312)
at javax.swing.Timer$DoPostEvent.run(Timer.java:244)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:738)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:699)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:708)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Caused by: java.lang.NullPointerException
at searchapp.searchWorker.search(searchWorker.java:65)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.search(searchWorker.java:66)
at searchapp.searchWorker.doInBackground(searchWorker.java:51)
at searchapp.searchWorker.doInBackground(searchWorker.java:21)
at javax.swing.SwingWorker$1.call(SwingWorker.java:296)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at javax.swing.SwingWorker.run(SwingWorker.java:335)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
//New Code
public class searchWorker extends SwingWorker<List<File>, File> {
protected static final FileFilter DIRECTORY_FILE_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
private DefaultListModel model;
private File path;
private FileFilter filefilter;
public searchWorker(File path, FileFilter filter, DefaultListModel model) {
this.model = model;
this.path = path;
this.filefilter = filter;
}
@Override
protected void process(List<File> chunks) {
for (File file : chunks) {
model.addElement(file);
}
}
@Override
protected List<File> doInBackground() throws Exception {
return new ArrayList<>(search(path));
}
public List<File> search(File path) {
List<File> files = new ArrayList<>(25);
if (path.exists()) {
File[] list = path.listFiles(filefilter);
if (list != null && list.length > 0) {
files.addAll(Arrays.asList(list));
publish(list);
}
File[] dirs = path.listFiles(DIRECTORY_FILE_FILTER);
for (File dir : dirs) {
files.addAll(search(dir));
}
}
return files;
}
}
private void searchBtnActionPerformed(java.awt.event.ActionEvent evt) {
searchWorker worker = new searchWorker(new File("c:\\"), new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".txt") && pathname.getName().startsWith("abc");
}
}, lm);
worker.execute();
}
//old code
DefaultListModel lm = new DefaultListModel();
public void search(String path) {
File root = new File(path);
File[] list = root.listFiles();
if (list == null) {
return;
}
for (File f : list) {
if (f.isDirectory()) {
if (list == null) {
return;
}
search(f.getAbsolutePath());
} else {
if (f.getName().endsWith(".txt") && f.getName().startsWith("abc")) {
lm.addElement(f.getName());
System.out.println(f.getName());
found = true;
}
}
}
private void formWindowOpened(java.awt.event.WindowEvent evt) {
jList1.setModel(lm);
}
private void searchBtnActionPerformed(java.awt.event.ActionEvent evt) {
//just added this code in my program to resolve unresponsive UI
Thread t = new Thread(new Runnable() {
@Override
public void run() {
search("c:\\");
}
});
t.start();
}
基本问题是,无论如何你实际上并没有修改
ListModel
。
Swing 是单线程环境,您使用了
Thread
来确保执行搜索时 UI 不会被阻塞,这很好,但 Swing 也不是线程安全的,这意味着您不应该更新UI 来自事件调度线程的上下文之外,因此 Thread
很糟糕。
虽然您“可以”使用
Thread
,但 SwingWorker
将为问题提供更好(通常更简单)的解决方案(更不用说更可重用的解决方案)
public static class SearchWorker extends SwingWorker<List<File>, File> {
protected static final FileFilter DIRECTORY_FILE_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
private DefaultListModel model;
private File path;
private FileFilter fileFilter;
public SearchWorker(File path, FileFilter filter, DefaultListModel model) {
this.model = model;
this.path = path;
this.fileFilter = filter;
}
@Override
protected void process(List<File> chunks) {
for (File file : chunks) {
model.addElement(file);
}
}
@Override
protected List<File> doInBackground() throws Exception {
return new ArrayList<>(search(path));
}
public List<File> search(File path) {
List<File> files = new ArrayList<>(25);
if (path.exists() && path.isDirectory()) {
File[] list = path.listFiles(fileFilter);
if (list != null && list.length > 0) {
files.addAll(Arrays.asList(list));
publish(list);
}
File[] dirs = path.listFiles(DIRECTORY_FILE_FILTER);
if (dirs != null) {
for (File dir : dirs) {
files.addAll(search(dir));
}
}
}
return files;
}
}
然后你只需使用类似的东西来启动它......
SearchWorker worker = new SearchWorker(new File("c:\\"), new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".txt") && pathname.getName().startsWith("abc");
}
}, lm);
worker.execute();
请参阅工作线程和 SwingWorker 了解更多详细信息
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
DefaultListModel model = new DefaultListModel();
JList list = new JList(model);
setLayout(new BorderLayout());
add(new JScrollPane(list));
JLabel label = new JLabel("...");
add(label, BorderLayout.SOUTH);
SearchWorker worker = new SearchWorker(new File("c:\\"), new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".png");
}
}, model);
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
SearchWorker worker = (SearchWorker) evt.getSource();
if ("state".equals(evt.getPropertyName())) {
if (worker.isDone()) {
label.setText("Finished");
try {
List<File> files = worker.get();
} catch (Exception e) {
e.printStackTrace();
}
}
} else if ("path".equals(evt.getPropertyName())) {
File path = (File) evt.getNewValue();
label.setText(path.toString());
}
}
});
worker.execute();
}
}
public static class SearchWorker extends SwingWorker<List<File>, File> {
protected static final FileFilter DIRECTORY_FILE_FILTER = new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
private DefaultListModel model;
private File path;
private FileFilter fileFilter;
public SearchWorker(File path, FileFilter filter, DefaultListModel model) {
this.model = model;
this.path = path;
this.fileFilter = filter;
}
@Override
protected void process(List<File> chunks) {
for (File file : chunks) {
model.addElement(file);
}
}
@Override
protected List<File> doInBackground() throws Exception {
return new ArrayList<>(search(path));
}
public List<File> search(File path) {
firePropertyChange("path", null, path);
List<File> files = new ArrayList<>(25);
if (path.exists() && path.isDirectory()) {
File[] list = path.listFiles(fileFilter);
if (list != null && list.length > 0) {
files.addAll(Arrays.asList(list));
publish(list);
}
File[] dirs = path.listFiles(DIRECTORY_FILE_FILTER);
if (dirs != null) {
for (File dir : dirs) {
files.addAll(search(dir));
}
}
}
return files;
}
}
}
检查以下更改。
public void search(String path) {
//DefaultListModel lm = new DefaultListModel();
//If you are not using the model for other purposes you can declare it here itself
//to clear the previous values if any [this is why repetitive values]
lm.clear();
File root = new File(path);
File[] list = root.listFiles();
if (list == null) {
return;
}
for (File f : list) {
if (f.isDirectory()) {
// Unnecessary test for null
// if (list == null) {
// return;
// }
search(f.getAbsolutePath());
} else {
if (f.getName().endsWith(".txt") && f.getName().startsWith("abc")) {
lm.addElement(f.getName());
System.out.println(f.getName());
found = true;
}
}
}
jList1.setModel(lm);
}