我正在制作这个JavaFX质量计算器,它基本上由一个按钮执行SwingWorker
后台线程来计算某些比率或因子或其他因素。
我已经意识到,对于我的因子和素因子计算(当我试图找到用户输入的数字的所有因子和素因子时),我在计算完成后得到NullPointerException
表演大约3-5次。
这是单击按钮时执行的脚本:
public static longCalculationThread calculationThread;
//Called by the calculate button
@FXML
void callCalculation(ActionEvent event) throws IOException, InterruptedException {
Long number = 0L;
Long lowerBound = 0L;
Long higherBound = 0L;
try {
//Bunch of input verification logic here. The logic here also creates the variables for the thread bundle
//Enabling progress UI since no errors were encoundered...
excelPane.setVisible(false);
progressPane.setDisable(false);
progressPane.setVisible(true);
//Preparing threadBundle, which is just a bunch of fields out into a data holding class [not shown]
calculationThread = new longCalculationThread(threadBundle);
calculationThread.execute();
System.gc(); //For the objects of the previous calculationThread
}
}
以下是longCalculationThread
的结构:
package PrimusForPC;
public class longCalculationThread extends SwingWorker<Void, Void> {
private ArrayList<Long> longResults = new ArrayList<>();
private ArrayList<String> stringResults = new ArrayList<>();
private calculationHolder.calculationType type;
private JFXProgressBar progressBar;
private Text progressText;
private GridView<String> answerGridView;
private Pane mainPane, progressPane;
private long mainNumber, lowerNum, upperNum;
private boolean shouldExport;
private ExcelWriter.spreadsheetTypes exportType;
private int excelExportLimit;
private JFXButton calcButton;
private Menu selectionMenu;
private static double acceptableAccuracy = 0.004; //The degree of accuracty for pi and phi couples
public static final double PHI = 1.6180339887498948482045;
public boolean shouldDie; //Called externally to kill the thread. Hasn't been implemented yet
longCalculationThread(threadArgumentBundle bundle){
progressBar = bundle.progressBar;
answerGridView = bundle.answerGridView;
type = bundle.type;
mainNumber = bundle.primaryNumber;
upperNum = bundle.upperNum;
lowerNum = bundle.lowerNum;
progressText = bundle.progressText;
mainPane = bundle.mainPane;
progressPane = bundle.progressPane;
exportType = bundle.exportType;
shouldExport = bundle.shouldExport;
excelExportLimit = bundle.excelExportLimit;
calcButton = bundle.button;
selectionMenu = bundle.selectionMenu;
}
@Override
public Void doInBackground(){
System.out.println("Thread started " + Thread.currentThread().getName());
Platform.runLater(new Runnable() {
@Override
public void run() {
progressBar.isIndeterminate();
progressBar.progressProperty().setValue(0);
calcButton.setDisable(true);
selectionMenu.setDisable(true);
}
});
switch (type){
case factors:
findfactors();
break;
case primeFactors:
findPrimeFactors();
break;
case primesUpToX:
findPrimesUpToX();
break;
//Bunch of other cases here...
}
try {
publishResults();
} catch (IOException | InterruptedException ex) {
Logger.getLogger(longCalculationThread.class.getName()).log(Level.SEVERE, null, ex);
}
reEndableInterface();
System.gc();
System.out.println("Thread ended " + Thread.currentThread().getName() + "\n");
return null;
}
static private long getSquareRoot (long number){
//For calculations square root only matters for larger numbers
//for numbers below 5 it doesn't really matter
if (number > 5){
number = (long) Math.ceil(Math.sqrt(number));
}
return number;
}
private void findfactors(){
progressText.setText("Finding factors...");
long root = getSquareRoot(mainNumber);
double incrementValue = 1/(double)root;
for (long divisor = 1; divisor <= root; divisor++) {
setProgressBar(progressBar.getProgress() + incrementValue);
if (mainNumber % divisor == 0) {
longResults.add(divisor);
longResults.add((mainNumber/divisor));
}
}
}
private void findPrimeFactors(){
findfactors();
progressText.setText("Separating prime factors from composite factors...");
progressBar.progressProperty().set(0);
double incrementValue = 1/(double)longResults.size();
ArrayList <Long> realResults = new ArrayList<>();
for (long factor: longResults){
if (isPrime(factor)) realResults.add(factor);
setProgressBar(progressBar.getProgress() + incrementValue);
}
longResults = realResults;
}
static boolean isPrime(long number){
if (number == 1) return false;
if (number == 2 || number == 3 || number == 5) return true;
long root = getSquareRoot(number);
for (int divisor = 2; divisor <= root; divisor++)
if (number % divisor == 0) return false;
return true;
}
private void publishResults() throws IOException, InterruptedException{
Platform.runLater(new Runnable() {
@Override
public void run() {
answerGridView.getItems().setAll(stringResults);
}
});
//To make UI interface useable again
private void reEndableInterface(){
Platform.runLater(new Runnable() {
@Override
public void run() {
progressPane.setDisable(true);
progressPane.setVisible(false);
mainPane.setDisable(false);
mainPane.setVisible(true);
calcButton.setDisable(false);
System.out.println("Button enabled " + Thread.currentThread().getName());
selectionMenu.setDisable(false);
}
});
}
我不确定NullPointerException
来自哪里,或者为什么它似乎只是在我使用&#34;发现因素&#34;或者&#34;找到素数因素&#34;计算。这是一个错误日志(对不起,这么久,不知道在哪里切断)。
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.text.PrismTextLayout.addTextRun(PrismTextLayout.java:755)
at com.sun.javafx.text.GlyphLayout.addTextRun(GlyphLayout.java:140)
at com.sun.javafx.text.GlyphLayout.breakRuns(GlyphLayout.java:312)
at com.sun.javafx.text.PrismTextLayout.buildRuns(PrismTextLayout.java:770)
at com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1021)
at com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:223)
at com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:246)
at javafx.scene.text.Text.getLogicalBounds(Text.java:358)
at javafx.scene.text.Text.impl_computeGeomBounds(Text.java:1168)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.updateTxBounds(Node.java:3641)
at javafx.scene.Node.getTransformedBounds(Node.java:3424)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1724)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1588)
at javafx.scene.Parent.recomputeBounds(Parent.java:1527)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1380)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.updateTxBounds(Node.java:3641)
at javafx.scene.Node.getTransformedBounds(Node.java:3424)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1724)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1588)
at javafx.scene.Parent.recomputeBounds(Parent.java:1527)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1380)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.updateTxBounds(Node.java:3641)
at javafx.scene.Node.getTransformedBounds(Node.java:3424)
at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1724)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1588)
at javafx.scene.Parent.recomputeBounds(Parent.java:1527)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1380)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078)
at javafx.scene.Node.updateGeomBounds(Node.java:3577)
at javafx.scene.Node.getGeomBounds(Node.java:3530)
at javafx.scene.Node.getLocalBounds(Node.java:3478)
at javafx.scene.Node.impl_intersectsBounds(Node.java:5013)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2931)
at javafx.scene.Node.impl_pickNode(Node.java:4912)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2936)
at javafx.scene.Node.impl_pickNode(Node.java:4912)
at javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3899)
at javafx.scene.Scene$MouseHandler.access$1600(Scene.java:3485)
at javafx.scene.Scene.pick(Scene.java:1942)
at javafx.scene.Scene.access$6700(Scene.java:159)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3799)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$355(GlassViewEventHandler.java:388)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
然后最后控制台只是垃圾邮件:
java.lang.ArrayIndexOutOfBoundsException
无限期。
正如我所说,我真的不知道为什么会这样。计算最初几次,然后发生此错误并冻结应用程序,需要完全重启。
答案 0 :(得分:0)
感谢评论我的问题的人 - 链接显示了问题!
我使用的是SwingWorker,因为我希望能够直接影响UI线程(因为如果反复且频繁地调用,Program.runLater可能会泛滥UI线程。)
事实证明,SwingWorkers在JavaFX中不具备该功能,所以我试图直接影响UI线程导致了这些错误。所以,我回到使用Thread,并使用了注释中链接提供的限制逻辑。这允许我在线程中使用Program.runLater而不会泛滥UI线程。