I've written a swing worker with the job of computing some text-statistics and afterwards updating a GUI element in the EDT with the results.
After some experimenting I found out that you should manipulate the GUI only in the done()
method, not in the doInBackground()
. In order to achieve that I remodeled the worker to have a return value String[]
, which I should be able to grab with get()
.
Apart from some publish()
methods you might find some bad calls from the doInBackground()
method manipulating the GUI directly, and if you think that my problem might be caused by that - let me know.
package my.worker;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import my.tools.CountKeywords;
import my.tools.FilterStopwords;
import my.tools.KeywordSuggestion;
import my.tools.RelevanceRanking;
public class ProcessDatabaseWorker extends SwingWorker<String[], String> {
private final JLabel debugJLabel;
private final JLabel infoJLabel;
private final JLabel warnJLabel;
private final JLabel errorJLabel;
private final JLabel infoboxJLabel;
private final String databaseString;
private final JProgressBar jProgressBar;
private final JComboBox keywordJComboBox;
private int percent;
private int index;
public ProcessDatabaseWorker(JProgressBar jProgressBar, String databaseString,
JLabel debugJLabel, JLabel errorJLabel, JLabel warnJLabel,
JLabel infoJLabel, JLabel infoboxJLabel,
JComboBox keywordJComboBox) {
this.percent = 1;
this.jProgressBar = jProgressBar;
this.databaseString = databaseString;
this.debugJLabel = debugJLabel;
this.errorJLabel = errorJLabel;
this.infoJLabel = infoJLabel;
this.warnJLabel = warnJLabel;
this.infoboxJLabel = infoboxJLabel;
this.keywordJComboBox = keywordJComboBox;
}
@Override
protected String[] doInBackground() throws Exception {
FilterStopwords fs = new FilterStopwords();
CountKeywords ck = new CountKeywords();
RelevanceRanking rr = new RelevanceRanking();
HashMap<String, Integer> nKeywords = new HashMap();
Map<String, TreeSet<Map.Entry<String, Double>>> keywordsPerDocument = new HashMap();
String replace = databaseString.toLowerCase();
String splitter = ("\\n");
String[] documentLines = replace.split(splitter);
int N = documentLines.length;
publish("Stopworte werden gefiltert...", "10");
String[] completeFilteredText = fs.filterStopwords(replace);
publish("Keywords werden gezählt...", "20");
HashMap<String, Integer> completeKeywords = ck.countKeywords(completeFilteredText);
index = 0;
percent = 1;
final double oneLinePercent = N / 100;
final double oneKeywordPercent = completeKeywords.size() / 100;
completeKeywords.forEach((String key, Integer value) -> {
int n = 0;
key = String.valueOf(key).trim();
for (String line : documentLines) {
String[] lineWords = line.split(" ");
for (String word : lineWords) {
word = word.trim();
if (word.equals(key)) {
n++;
nKeywords.put(key, n);
}
}
}
index++;
if (index == oneKeywordPercent) {
percent++;
publish("Zählung...", String.valueOf(percent));
index = 0;
}
});
publish("Keywords werden geranked...", "40");
index = 0;
percent = 1;
for (String documentLine : documentLines) {
TreeSet<Map.Entry<String, Double>> rankedKeywords;
String[] lineFilteredWords = fs.filterStopwords(documentLine);
HashMap<String, Integer> keywords = ck.countKeywords(lineFilteredWords);
rankedKeywords = rr.rankKeywords(keywords, lineFilteredWords, N, nKeywords);
keywordsPerDocument.put(documentLine, rankedKeywords);
index++;
if (index == oneLinePercent) {
percent++;
publish("Ranking...", String.valueOf(percent));
index = 0;
}
}
publish("Keyword-Vorschläge werden generiert...", "70");
KeywordSuggestion ks = new KeywordSuggestion();
TreeSet<Map.Entry<String, Double>> keywordSuggestionsTree = ks.keywordSuggestion(keywordsPerDocument);
String[] keywordSuggestionsArray = new String[keywordSuggestionsTree.size()];
index = 0;
int index2 = 0;
double onePercent = keywordSuggestionsTree.size() / 100;
percent = 1;
publish("Keyword-Vorschläge werden generiert...", "75");
for (Map.Entry<String, Double> entry : keywordSuggestionsTree) {
double round = round(entry.getValue(), 2);
keywordSuggestionsArray[index2] = round + " - " + entry.getKey();
index2++;
index++;
if (index == onePercent) {
percent++;
publish("Keywords...", String.valueOf(percent));
index = 0;
}
}
keywordJComboBox.removeAllItems();
for (String entry : keywordSuggestionsArray) {
publish("Keyword-Vorschläge werden befüllt...", "80");
}
This is the line returning the value I need for the get()...
return keywordSuggestionsArray;
}
public static double round(double value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
@Override
public void process(List<String> s) {
infoboxJLabel.setText(s.get(0));
jProgressBar.setValue(Integer.valueOf(s.get(1)));
}
@Override
protected void done() {
try {
Here's the point where the NullPointerException is thrown...
String[] get = get();
for (String entry : get) {
keywordJComboBox.addItem(entry);
}
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(ProcessDatabaseWorker.class.getName()).log(Level.SEVERE, null, ex);
}
publish("Verarbeitung der Daten abgeschlossen!", "100");
}
}
For further information here's the complete trace:
Apr 14, 2016 10:40:06 AM my.worker.ProcessDatabaseWorker done
SCHWERWIEGEND: null
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at javax.swing.SwingWorker.get(SwingWorker.java:602)
at my.worker.ProcessDatabaseWorker.done(ProcessDatabaseWorker.java:197)
at javax.swing.SwingWorker$5.run(SwingWorker.java:737)
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:313)
at javax.swing.Timer$DoPostEvent.run(Timer.java:245)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.lang.NullPointerException
at my.logfileanalyzer.LogFileAnalyzerGUI.keywordJComboBoxItemStateChanged(LogFileAnalyzerGUI.java:830)
at my.logfileanalyzer.LogFileAnalyzerGUI.access$2400(LogFileAnalyzerGUI.java:48)
at my.logfileanalyzer.LogFileAnalyzerGUI$15.itemStateChanged(LogFileAnalyzerGUI.java:329)
at javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223)
at javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1271)
at javax.swing.JComboBox.contentsChanged(JComboBox.java:1330)
at javax.swing.JComboBox.intervalRemoved(JComboBox.java:1352)
at javax.swing.AbstractListModel.fireIntervalRemoved(AbstractListModel.java:179)
at javax.swing.DefaultComboBoxModel.removeAllElements(DefaultComboBoxModel.java:174)
at javax.swing.JComboBox.removeAllItems(JComboBox.java:771)
at my.worker.ProcessDatabaseWorker.doInBackground(ProcessDatabaseWorker.java:165)
at my.worker.ProcessDatabaseWorker.doInBackground(ProcessDatabaseWorker.java:43)
at javax.swing.SwingWorker$1.call(SwingWorker.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javax.swing.SwingWorker.run(SwingWorker.java:334)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Now, for my question: which part of the worker didn't I use correct or where did I go wrong with my program-logic? As you can see i am pretty new to programming with swing workers and threads in general, so I'm sure there is a simple solution for a simple mistake caused by inexperience.
Furthermore, let me know, if any other parts of my program are needed, in order to paint a better picture about what's going on.
EDIT: error was exactly where user Moh-Aw described - edited my code as following fixing it:
private void keywordJComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {
if (keywordJComboBox.getItemCount() != 0){
if (!((String) keywordJComboBox.getSelectedItem()).equals("")) {
String selected = (String) keywordJComboBox.getSelectedItem();
String[] blubb = selected.split(" ");
searchJTextField.setText(blubb[2]);
}
}
}
EDIT: Concerning the possible duplicate - i'm pretty sure that this post is. I honestly thought it was a wrong implementation of swing workers
, not something as simple as it actually was - so this post may as well be closed ^^