I have started to work on my first Java program, which is a simple calculator, however I get an error claiming that my array is out of bounds. I have tried to debug it to see where and why that is so, as well as following the code on paper, both of which display the results that I would expect and wish for. Therefore, I can not see where the problem actually lies. The code is not complete.
According to the debugger, the error occurs at this line:
answer = outputNum.get(operationIndex) * outputNum.get(operationIndex+1);
Here is the main part of the code that I currently have:
private class ButtonHandler implements ActionListener {
/*
* "outputNum" stores the numbers entered in order.
* "orderOfOperations" stores all numbers in order after multiplication and division has been taken care of.
* "operationList" stores the mathematical operations entered in order.
* "currentNum" stores the most recently inputed numbers.
* "currentString" stores the most recently inputed string of numbers.
* "answer" stores temporary values and ultimately the answer to the inputed equation.
* "start" stores whether or not the equals button has been pressed and a new equation has started.
*/
ArrayList <Double> outputNum = new ArrayList <Double> (0);
ArrayList <Double> orderOfOperations = new ArrayList <Double> (0);
ArrayList <String> operationList = new ArrayList <String> (0);
Double currentNum = 0.0;
String currentString = "0";
Double answer = 0.0;
boolean start = false;
public void actionPerformed(ActionEvent event) {
if(event.getSource() == equalsBtn) {
/* Takes the current numbers string and convert it into a double.
* Let the order of operations be the inputed order for now.
* "operationIndex" to get values inside of the unchanging arrays "outputNum" and "operationList".
* "orderIndex" to get values inside of the changing array "orderOfOperations".
*/
currentNum = Double.parseDouble(currentString);
outputNum.add(currentNum);
orderOfOperations = outputNum;
int operationIndex = 0;
int orderIndex = 0;
//Cycle through the mathematical operations that occur in the current equation.
for(String operation : operationList) {
if(operation == "x" || operation == "รท") {
// Multiply/divide numbers with the multiply/divide operations together.
if(operation == "x") {
answer = outputNum.get(operationIndex) * outputNum.get(operationIndex+1);
}
else {
answer = outputNum.get(operationIndex) / outputNum.get(operationIndex+1);
}
// Replace numbers multiplied/divided in the above statement with the new answer.
orderOfOperations.remove(orderIndex);
orderOfOperations.set(orderIndex, answer);
orderIndex++;
}
operationIndex++;
}
// Reset variables to the default values for the new equation.
System.out.println(orderOfOperations);
outputString = answer.toString();
answer = 0.0;
currentNum = 0.0;
currentString = "0";
outputNum.clear();
operationList.clear();
orderOfOperations.clear();
start = true;
}
else if(event.getSource() == additionBtn || event.getSource() == subtractionBtn || event.getSource() == multiplicationBtn || event.getSource() == divisionBtn) {
// Sets the text fields text blank if this is the start of a new equation.
if(start) {
outputString = "";
start = false;
}
/*
* Takes the current numbers string and convert it into a double.
* Add the mathematical operation and reset the current number.
*/
currentNum = Double.parseDouble(currentString);
outputNum.add(currentNum);
operationList.add(event.getActionCommand());
currentString = "0";
outputString = String.format("%s%s", outputString, event.getActionCommand());
}
else {
// Sets the text fields text blank if this is the start of a new equation.
if(start) {
outputString = "";
start = false;
}
// Adds the button value to the text field text and the current number being inputed.
currentString = String.format("%s%s", currentString, event.getActionCommand());
outputString = String.format("%s%s", outputString, event.getActionCommand());
}
outputScreen.setText(outputString);
}
}
Here is the error message that I get:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at MainWindow$ButtonHandler.actionPerformed(MainWindow.java:141)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6414)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3275)
at java.awt.Component.processEvent(Component.java:6179)
at java.awt.Container.processEvent(Container.java:2084)
at java.awt.Component.dispatchEventImpl(Component.java:4776)
at java.awt.Container.dispatchEventImpl(Container.java:2142)
at java.awt.Component.dispatchEvent(Component.java:4604)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4618)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4279)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4209)
at java.awt.Container.dispatchEventImpl(Container.java:2128)
at java.awt.Window.dispatchEventImpl(Window.java:2492)
at java.awt.Component.dispatchEvent(Component.java:4604)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:717)
at java.awt.EventQueue.access$400(EventQueue.java:82)
at java.awt.EventQueue$2.run(EventQueue.java:676)
at java.awt.EventQueue$2.run(EventQueue.java:674)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:690)
at java.awt.EventQueue$3.run(EventQueue.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:687)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
When operationIndex is equal to the last element index in outputNum, then operationIndex + 1 will be greater than the last element index: hence your exception
You would be better off using a for loop that started at index 1, and doing:
// assuming that operationList and outputNum always
// have the same number of elements
for (int i = 1; i < operationList.size(); i++) {
...
answer = outputNum.get(i - 1) * outputNum.get(i);
...
}
or, alternatively, use your current loop, but do:
// operationIndex++; // remove this and use ..
if (++operationIndex >= outputNum.size()) break;
You are only ever adding one item to your list:
currentNum = Double.parseDouble(currentString);
outputNum.add(currentNum);
Then you try to access what seems to be a second object at index operationindex +1 which doesn't exist:
answer = outputNum.get(operationIndex) * outputNum.get(operationIndex+1);
Related
I'm currently working on an assignment that requires me to build a small database for an imaginary toy company. They sell four different types of toys, with all of their toy's data in a single text file. Different toys have varying attributes to them.
My job is to read every line of the text file, find out what toy it is based on it's serial number, create a new instance of that toy, and load it into an array list of Toys.
Here are some examples of a line in the .txt file for every type of toy.
Animal
2835360879;Cow;Game Assassin;19.52;3;7;Plastic;M
Puzzle
4353818087;Eight queens puzzle;Gamescape;15.69;5;6;C
Figure
1147205649;Ninja Turtles;Gamezoid;46.15;10;6;A
Board Game
7235647474;13 Dead End Drive;Game Assassin;55.18;10;9;1-8;Emeli Davis
The following method is in charge of parsing through the text file, to create new instances of Toy, and to add them into the Array List
public void loadData() {
try {
File dataFile = new File("res/toys.txt");
if (dataFile.createNewFile()) {
System.out.println("Data file created!");
}
else {
Scanner readData = new Scanner(dataFile);
readData.useDelimiter(";"); // sets semicolons as the delimiter
while(readData.hasNext()) {
sn = readData.nextDouble(); // reads the next double (serial number) on each line
category = categoryHandler(sn); // setting and returning value for category based on the serial number
nm = readData.next(); // initializes the name of the toy
brd = readData.next();
prc = readData.nextDouble();
availableCnt = readData.nextInt();
ageApp = readData.nextInt();
// creates a new object, dependant on the category
switch(category) {
case "Figures":
char classification = readData.next().charAt(0);
Figure figures = new Figure(sn, nm, brd, prc, availableCnt, ageApp, classification);
data.add(figures);
break;
case "Animals":
String material = readData.next();
char size = readData.next().charAt(0);
Animal animals = new Animal(sn, nm, brd, prc, availableCnt, ageApp, material, size);
data.add(animals);
break;
case "Puzzles":
char puzzleType = readData.next().charAt(0);
Puzzle puzzles = new Puzzle(sn, nm, brd, prc, availableCnt, ageApp, puzzleType);
data.add(puzzles);
break;
case "Board Games":
String playerCount = readData.next(); // holds the player count as a string
int minPlayers = Integer.parseInt(playerCount.substring(0, 1)); // holds the first integer
int maxPlayers = Integer.parseInt(playerCount.substring(playerCount.length() - 1, playerCount.length())); // holds the second integer
String designers = "";
BoardGame boardGames = new BoardGame(sn, nm, brd, prc, availableCnt, ageApp, minPlayers, maxPlayers, designers);
data.add(boardGames);
break;
default:
System.out.println("Invalid toy type selected!");
}
if (readData.hasNext()) {
readData.nextLine(); // skips to the next line if there's a line to skip to
}
}
readData.close();
}
}
catch (IOException e) {
System.out.println("An error occured.");
e.printStackTrace();
}
}
The following method is in charge of categorizing the toy type.
public String categoryHandler(double serialNumber) {
String serialNumCheck = Double.toString(serialNumber); // converting serial number to string to allow the first digit to be checked
double firstDigit;
// setting up the first digit, checking to see if it's zero.
if (serialNumCheck.length() == 12) {
firstDigit = 0;
}
else {
firstDigit = Double.parseDouble(Double.toString(serialNumber).substring(0, 1));
}
// conditionals
if (firstDigit == 0 || firstDigit == 1) {
category = "Figures";
}
else if (firstDigit == 2 || firstDigit == 3) {
category = "Animals";
}
else if (firstDigit == 4 || firstDigit == 5 || firstDigit == 6) {
category = "Puzzles";
}
else if (firstDigit == 7 || firstDigit == 8 || firstDigit == 9) {
category = "Board Games";
}
// this condition should not be possible to achieve, unless the first digit is negative. Still have it just in case.
else {
System.out.println("Invalid serial number created!");
category = "";
}
return category;
}
After running the loadData() method, my array list only contains 128 toys, instead of the expected 225. Almost all of them are categorized properly, but a few toys are not, at seemingly at random indices.
I suspect it has something to with readData.nextLine() at the end of the loadData() method. The problem is that when I remove the line, the program throws a NullPointerException as there nothing left to scan on the current line, so no Toy can be created.
At this point I'm fairly lost as to what is causing this bug.
Some guidance would be appreciated.
I was expecting get the lowest run time, but instead it prints the very last entree in the arrayList. I'm trying to print a specific course for the dogs and that works when I enter the course code. However, the lowest run time seem to not work.
example data
Lazlo 12.2
Rin 34.2
Yu 23.3 - This will be printed as the winning dog when Lazlo should be the winning dog.
The winning dog should have the lowest run time, but it takes in the last read line instead and prints it.
private void winningDog(String dogsCode)
{
double runTime = 300;
String winningDog = "";
double winningTime = 0;
for (Dogs dog: dogsList)
{
if(runTime > dog.getTotalTime() && (dog.getCourseCode().equalsIgnoreCase(dogsCode)))
{
winningTime = dog.getTotalTime();
winningDog = dog.getName();
}
}
System.out.printf("%n%s%17s%20s%1.2f%n",
"Winning dog", winningDog,"Time " , winningTime);
}
Assuming you don't have negative values for dog.getTotalTime(), you can change your code
winningTime = Double.MAX_VALUE; //assigning MAX value to ensure the condition is met at least once(unless all your time values are MAX_VALUE)
and then update your condition as
if(runTime > dog.getTotalTime()..
to
if(winningTime > dog.getTotalTime().. // this would compare winningTime and you're setting the same is the condition matches
What you're trying to do is basically finding the minimum field of some object. You can do this in one line using the new Java 8 Stream API.
Dogs winningDog = dogsList.stream().min(Comparator.comparingInt(Dogs::getTotalTime)).get();
Your class Dogs should probably be Dog. I'm just basing my response based off your enhanced for-loop, where it says Dogs dog: dogsList.
Your filter in the for-loop can easily be chained into the call by adding a .filter( CONDITIONS ) in-between .stream() and .min().
private void winningDog(String dogsCode) {
String winningDog = "";
double winningTime = 0;
if (dogsList != null) {
winningTime = dogsList.get(0).getTotalTime();
winningDog = dogsList.get(0).getName();
if (dogsList.size() > 1) {
for (int i = 1; i < dogsList.size(); i++) {
if (dogsList.get(i).getTotalTime()< winningTime
&& (dogsList.get(i).getCourseCode().equalsIgnoreCase(dogsCode))) {
winningTime = dogsList.get(i).getTotalTime();
winningDog = dogsList.get(i).getName();
}
}
}
}
System.out.printf("%n%s%17s%20s%1.2f%n", "Winning dog", winningDog, "Time ", winningTime);
}
public void actionPerformed(ActionEvent e)
{
int clicked = 0;
if(arg == "Enter")
{
clicked++;
}
if (clicked == 0)
{
names[0] = nameField.getText();
numbers[0] = numberField.getText();
}
if( clicked == 1)
{
names[1] = nameField.getText();
numbers[1] = numberField.getText();
}
if(arg == "Print")
{
String name = nameField.getText();
String number = numberField.getText();
JOptionPane.showMessageDialog(null,names[0] + numbers[0] + names[1] + numbers[1] + numbers[2] + names[2],"Info",JOptionPane.INFORMATION_MESSAGE);
}
My program must take multiple names and numbers and be able to enter them into an array. After all of the data is entered, it must be able to be printed. I am having trouble under the Enter method because it continues to reset everytime instead of remaining constant. It only allows me to print the last typed name/number instead of saving all of the content. I am unsure of how to fix this and would be grateful for any suggestions at this point.
You could start by moving int clicked out of this function.
Right now your actionPerformed function each time its called reset your clicked to 0 since you are setting it to 0 at the beggining of it.
public void actionPerformed(ActionEvent e)
{
int clicked = 0; //HERE is your problem
if(arg == "Enter");
...
Making it a variable of class instead of function should help.
EDIT:
You can do something like this:
int clicked = 0
public void actionPerformed(ActionEvent e)
{
if(arg == "Enter"){
names[clicked] = nameField.getText();
numbers[clicked] = numberField.getText();
clicked++;
}
As it was mentioned you could also use List, since it would save problems if you don't know how big of an array u need.
List<String> names = new ArrayList<String>();
List<String> numbers = new ArrayList<String>();
And in use
if(arg == "Enter"){
names.add(nameField.getText());
numbers.add(numberField.getText());
}
Instead of an array, you could use an ArrayList, it will allow you to add elements without having to supply an index.
Without givening away too much, like this:
ArrayList<String> names = new ArrayList<String>();
...
names.add("Johnny"); // Adds to the end of the list
names.add("Frank");
That way you don't need to keep the 'clicked' count.
You can use .get(i) to get the element at index i. Or just loop over the entire list using a for each loop:
for(String name : names) { // i.e. for each 'name' in 'names'
System.out.println(name);
// Or do something else with 'name'
}
Here is the program that I am trying to run:
/**
* Write a description of class mainGame here.
*
* #author Anthony Parsch
* #version 0.1.1
*/
//Import what I need to.
import java.io.*;
public class mainGame
{
/**
* Constructor for objects of class mainGame
*/
public static void main(String[] args)
{
// initialise instance variables
int xCoord = 10; //The map's max x coordinate +1
int yCoord = 10; //The map's max y coordinate +1
int playerX = 0; //The player's current x coordinate
int playerY = 0; //The player's current y coordinate
//Declare the arrays
String[][] map; //[x][y]The map
String[][] direc; //[x][y]Which directions that you can go
String[][] items; //[x][y]Where items are at
String[] inv; // Holds your inventory.
int[][] helpInt; //[x][y] All the other stuff in the
//Initalize the arrays
//---The player arrays
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
//---The map arrays
map = new String[xCoord][yCoord]; //Descriptions
direc = new String[xCoord][yCoord]; //north y++,west x--,south y--,east x++
items = new String[xCoord][yCoord]; //The items within the world
//Declare the values of map
map[0][0] = "You wake up with the feel of cold metal on your back. The only other thing in this room is the door.";
map[0][1] = "You are now in a hallway with a door behind you and one either side. Forward is a continuation of the hallway.com";
//Declare the values of direc
direc[0][0] = "north";
direc[0][1] = "north, south, east, west";
print(inv[0]); //Check that the functions work
print(findDirec(direc, 0, 0));
}
/**
* Finds and displays the avaliable exits for a coordinate.
*
* #param map[][] The map array from which this method pulls the directions from.
* #param x The x value of the map
* #param y The y value of the map
* #return The string value of which way you can go
*/
static String findDirec(String[][] map, int x, int y){
//Pulls the directions
String match = map[x][y];
//Checks Directions
boolean nor = match.matches("(.*)north(.*)");
boolean sou = match.matches("(.*)south(.*)");
boolean wes = match.matches("(.*)west(.*)");
boolean eas = match.matches("(.*)east(.*)");
//Displays directions
String placeHolder = "You can go ";
if (nor == true){
placeHolder = placeHolder + "north, ";
} else if(sou == true) {
placeHolder = placeHolder + "south, ";
} else if(wes == true) {
placeHolder = placeHolder + "west, ";
} else if(eas == true) {
placeHolder = placeHolder + "east";
}
//---Checks if east is in the string, if not it removes the space and comma
if (eas == false){
StringBuffer soo = new StringBuffer(placeHolder);
soo.delete((placeHolder.length()-3), (placeHolder.length()-1));
placeHolder = soo.toString();
}
//Adds the ending period
placeHolder = placeHolder + ".";
//Returns the string
return placeHolder;
}
//Adds an item to an inventory
static String[] addItem(String inv[], String item){
int i; //Counter for the for loop, and where to add the item at.
boolean stop = false;
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
inv[i] = item;
return inv;
}
static void print(String entry){
System.out.print(entry);
}
}
And when I try and run it through the Command Prompt, I get this error:
Exception in thread "main" java.lang.NullPointerExcpetion
at mainGame.addItem(mainGame.java:113)
at mainGame.main(mainGame.java:38)
When I paste this in to a text editor, line 113 is simply a closing brace }.
However, one line before that is a logic flaw which I presume is really line 113 for you.
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
Each iteration of the loop assigns true to stop and then tests if true equals true, which it does. Your condition to exit the loop is when true equals false, which is never the case, therefore your loop goes forever until an error occurs. Also, don't you want to iterate while stop is false? I think you have it backwards.
The next problem is your if statement, which is probably where your NullPointerException is coming from:
if(inv[i].equals("0"))
{
stop = true;
}
You assume that inv[i] refers to an object. You need a null check.
Three recommendations:
Never use = for a comparison. Use ==. Since this is a boolean, you can even simplify this to stop.
Check the length in your for loop.
Compare "0" to inv[i] instead of the other way around to avoid null pointer dereferencing.
Try this:
boolean stop = false;
for (int i = 0; i < inv.length && !stop; i++)
{
if("0".equals(inv[i])
{
stop = true;
}
}
Another option, and this is a matter of form, is to remove the looping variable and just break out of the loop explicitly.
for (int i = 0; i < inv.length; i++)
{
if("0".equals(inv[i])
{
break;
}
}
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
So you only initialize one index of your array but here:
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
.. you loop through all of them. just kidding, didn't read the full problem. You should still read the rest of my answer, but the reason why you get the NPE is because your loop condition is broken. (by the way your for loop condition is broken, it should test for equivalence using the == operator, not the assignment = operator.)
So what you actually are doing with that code is this :
inv = new String[10];
At this point you have a new String array of capacity 10, with no values inside, something like this:
[null][null][null][null][null][null][null][null][null][null]
inv[0] = "0";
Now you set [0] to "0", so:
["0"][null][null][null][null][null][null][null][null][null]
Then your loop attempts to access all of those null references, that'll probably be why you have a null reference exception.
To fix it, simply every index position in your array to anything that is not-null:
Arrays.fill(inv, "");
I use Arrays.fill() because it's shorter.
In your for loop condition, which one do you prefer?
stop = true or stop == true
for(i=0; i<inv.length && !stop; i++)
{
if(inv[i]!=null && inv[i].equals("0"))
{
stop = true;
}
}
I created a java program that will convert decimal to binary and vice versa. I don't have any problems with my decimal to binary. But when I coded my binary to decimal I get the following errors:
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:470)
at java.lang.Integer.parseInt(Integer.java:499)
at converter.actionPerformed(converter.java:42)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6382)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3275)
at java.awt.Component.processEvent(Component.java:6147)
at java.awt.Container.processEvent(Container.java:2083)
at java.awt.Component.dispatchEventImpl(Component.java:4744)
at java.awt.Container.dispatchEventImpl(Container.java:2141)
at java.awt.Component.dispatchEvent(Component.java:4572)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4619)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4280)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4210)
at java.awt.Container.dispatchEventImpl(Container.java:2127)
at java.awt.Window.dispatchEventImpl(Window.java:2489)
at java.awt.Component.dispatchEvent(Component.java:4572)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:704)
at java.awt.EventQueue.access$400(EventQueue.java:82)
at java.awt.EventQueue$2.run(EventQueue.java:663)
at java.awt.EventQueue$2.run(EventQueue.java:661)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
at java.awt.EventQueue$3.run(EventQueue.java:677)
at java.awt.EventQueue$3.run(EventQueue.java:675)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:674)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class converter extends JFrame implements ActionListener {
JTextField txt1;
JTextField txt2;
JLabel lbl1;
JLabel lbl2;
JButton b1;
JButton b2;
public converter(){
Container c = getContentPane();
JPanel jp = new JPanel();
c.add(jp);
jp.add(lbl1=new JLabel("Decimal: "));
jp.add(txt1=new JTextField(10));
jp.add(lbl2=new JLabel("Binary: "));
jp.add(txt2=new JTextField(10));
jp.add(b1=new JButton("Convert"));
jp.add(b2=new JButton("Clear"));
b1.addActionListener(this);
b2.addActionListener(this);
}
public static void main(String[] args) {
converter cvt = new converter();
cvt.setResizable(false);
cvt.setVisible(true);
cvt.setSize(250,150);
cvt.setTitle("Decimal - Binary Converter");
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String num = txt1.getText();
int i = Integer.parseInt(num);
if(txt1 != null && e.getSource() == b1){
String z = Integer.toBinaryString(i);
txt2.setText(z);
}
else if(e.getSource() == b2){
txt1.setText("");
txt2.setText("");
}
else if(txt2 != null && e.getSource() == b1){
int x = Integer.parseInt(txt2.getText().trim(), 2);
txt1.setText(""+x);
}
}
}
Can you point out what is wrong? And what can be its solution.
You don't have any bounds checking in your code. Aka, you have two text inputs and one 'Convert' function, but the function is applicable for all the following combinations:
Decimal input and Binary input are both given
Decimal input and Binary input are both omitted
Decimal input is given, Binary input is omitted
Decimal input is omitted, Binary input is given
You need to decide what to do in all four cases, and then proceed with your parse appropriately. Three out of four of these cases are pretty straightforward to deal with - leaving you with having to make a decision about what to do when a user fills in both the Decimal and Binary input fields then hits Convert (I would recommend showing an error dialog in that case).
As it stands, you are parsing your Decimal input field in all cases, and when its left blank this translates to:
Integer.parseInt("")
Which throws a NumberFormatException, as expected.
I would handle your four possible scenarios something like this:
public static boolean isEmpty(final String str) {
return (str == null || str.trim().equals(""));
}
final String decimalInput = text1.getText();
final String binaryInput = text2.getText();
if(! isEmpty(decimalInput)) {
if( ! isEmpty(binaryInput)) {
// Decimal input and Binary input are both given, show error
} else {
// Decimal input is given, Binary input is omitted, convert to binary
}
} else {
if( isEmpty(binaryInput)) {
// Decimal input and Binary input are both omitted, show error
} else {
// Decimal input is omitted, Binary input is given, convert to decimal
}
}
Check txt1 and txt2 value if it's a number or not.
The first line of the trace shows that there is an error thrown when your program tries to convert an empty string ("") to an int. If you look further down the trace (on line 5), the error occurs in the actionPerformed method. Particularly, the lines:
String num = txt1.getText();
int i = Integer.parseInt(num);
You could solve this problems by first checking if the string is not empty with:
if (num.length() < 1)
// tell user they must enter a number
A few things jump to mind.
You could trap the exception and display a message telling the user that the value they entered is invalid. You should also trim the result from the field just to be sure.
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
try {
String num = txt1.getText().trim(); // <-- Trim the incoming value
int i = Integer.parseInt(num);
if(txt1 != null && e.getSource() == b1){
String z = Integer.toBinaryString(i);
txt2.setText(z);
}
else if(e.getSource() == b2){
txt1.setText("");
txt2.setText("");
}
// I'm not sure if this a logic error or not, but txt2 is text field...
// Did you think it was the text from the field??
else if(txt2 != null && e.getSource() == b1){
int x = Integer.parseInt(txt2.getText().trim(), 2);
txt1.setText(""+x);
}
} catch (NumberFormatException exp) {
// Display message...
}
}
The other is to use a DocumentFilter to prevent the user from entering any values that are invalid for the fields.
Check out Text Component Features and examples
Updated
You also have some logic errors...
txt1 and txt2 are never likely to be null, unless you've done something horrible wrong...
You should check to see what button was pressed first, that will allow you to make a clearer decision on how to progress.
You should then check the text from the fields and decide on which conversion path you want to go on...
try {
if (e.getSource() == b1) {
String dec = txt1.getText();
String bin = txt2.getText();
if (dec != null && dec.trim().length() > 0 &&
bin != null && bin.trim().length() > 0) {
// Both fields are filled out?!
} else if (dec != null && dec.trim().length() > 0) {
String value = txt1.getText();
int i = Integer.parseInt(dec);
String z = Integer.toBinaryString(i);
txt2.setText(z);
} else if (bin != null && bin.trim().length() > 0) {
int x = Integer.parseInt(bin, 2);
txt1.setText("" + x);
}
} else if (e.getSource() == b2) {
txt1.setText("");
txt2.setText("");
}
} catch (NumberFormatException exp) {
exp.printStackTrace();
}