First of all, I apologize because I am not sure I even know how to phrase my problem exactly. We have just started Object oriented programming in Uni and I'm having trouble with grasping the concept.
So the goal is to work get data from a .csv file. ( Periodic table )
The problem is that in the original file some fields are just empty. I am aware of the problem ( at least I think so) : The fileReader saves them as empty strings in to the array, and they get parsed in to my array list as a strings, while a type Double is expected. But I just don't know what to do.
: java.lang.NumberFormatException: empty String
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.base/java.lang.Double.parseDouble(Double.java:549)
at ChemicalElement.DAO.<clinit>(DAO.java:28)
I'm posting all the code I have in case there's something else wrong that I'm not aware of. All criticism (or advice) is welcome!
public class ChemicalElement {
private String element;
private int number;
private String symbol;
private double weight;
private double boil;
private double melt;
private double density;
private double vapour;
private double fusion;
public ChemicalElement()
{
}
public String GetElement()
{
return this.element;
}
public int GetNumber()
{
return this.number;
}
public String GetSymbol()
{
return this.symbol;
}
public double GetWeight()
{
return this.weight;
}
public double GetBoil()
{
return this.boil;
}
public double GetMelt()
{
return this.melt;
}
public double GetDensity()
{
return this.density;
}
public double GetVapour()
{
return this.vapour;
}
public double GetFusion()
{
return this.fusion;
}
public void SetElement(String element)
{
this.element = element;
}
public void SetNumber(int number)
{
this.number = number;
}
public void SetSymbol(String symbol)
{
this.symbol = symbol;
}
public void SetWeight(double weight)
{
this.weight = weight;
}
public void SetBoil(double boil)
{
this.boil = boil;
}
public void SetMelt(int melt)
{
this.melt = melt;
}
public void SetDensity(int density)
{
this.density = density;
}
public void SetVapour(double vapour)
{
this.vapour = vapour;
}
public void SetFusion(double fusion)
{
this.fusion = fusion;
}
public ChemicalElement(String element ,int number,String symbol, double weight, double boil,double melt , double density, double vapour, double fusion)
{
this.element = element;
this.number = number;
this.symbol = symbol;
this.weight = weight;
this.boil = boil;
this.melt = melt;
this.density = density;
this.vapour = vapour;
this.fusion = fusion;
}
public ChemicalElement(String element ,int number,String symbol, double weight, double boil,double melt , double density, double vapour)
{
this.element = element;
this.number = number;
this.symbol = symbol;
this.weight = weight;
this.boil = boil;
this.melt = melt;
this.density = density;
this.vapour = vapour;
}
public ChemicalElement(String element ,int number,String symbol, double weight)
{
this.element = element;
this.number = number;
this.symbol = symbol;
this.weight = weight;
}
#Override
public String toString()
{
return "Element{" + element + ", number= " + number + ", symbol= " + symbol + ", weight= " + weight + ", boil=" + ", melt= " + melt + "densitiy= " + density + ", vapour= " + vapour + "fusion= " + fusion + '}';
}
}
public class DAO {
public static List<ChemicalElement> elements = new ArrayList<>();
static {
try
{
Scanner scan = new Scanner(new FileReader("elements2.csv"));
String firstLine = scan.nextLine(); //skip first line ( title )
while(scan.hasNext())
{
String readFile[] = scan.nextLine().split(",");
if(readFile.length == 4)
{
ChemicalElement El = new ChemicalElement(readFile[0],Integer.parseInt(readFile[1]),readFile[2],Double.parseDouble(readFile[3]));
elements.add(El);
}
else if(readFile.length == 8)
{
//first exception is down below
ChemicalElement El = new ChemicalElement(readFile[0],Integer.parseInt(readFile[1]),readFile[2],Double.parseDouble(readFile[3]),Double.parseDouble(readFile[4]),Double.parseDouble(readFile[5]),Double.parseDouble(readFile[6]),Double.parseDouble(readFile[7]));
}
else
{
for(int i = 0; i < readFile[i].length(); i++)
{
if(readFile[i].equals(""))
{
readFile[i].replace("","0"); // what to do here ?
}
}
}
}
}
catch (FileNotFoundException ex)
{
System.out.println(ex.getMessage());
}
}
public static void PeriodicTable() {
for (ChemicalElement element : elements) {
System.out.println(element);
}
}
}
public class Main {
public static void main(String[] args) {
DAO.PeriodicTable(); // Just trying to at least print all elements on the list
}
}
EDIT! Adding my .csv file as requested: Not sure about the version of Java,but my IDE is IntelliJ
What's happening is as I can see is, the CSV file probably has a column for 'weight' of the element. But value for this column must be empty in at least one of the rows. So when it tries to parse the string value for the weight (or any other double field) it's throwing a numberFormatException. To correct this see if the CSV file adheres to the constraints you enforce on code OR do a round of validation for each row and set the correct default values
Basically your code has to handle all the unexpected cases including, for example, missing values or invalid values. Parsing a CSV file is not as simple as it at first seems. That is why there are utilities for parsing CSV files such as opencsv
Refer to my last comment to your question. I assume that you are using a comma as the delimiter and I also assumed that the delimiter in the image in your question is a tab and so I changed the tab characters in file elements2.csv to commas.
Also, I only took a few lines from the file including the following.
Element,Number,Symbol,Weight,Boil,Melt,Density,Vapour,Fusion
Hydrogen,1,H,1.01,20.46,13.96,71,0.45,0.06
Carbon,6,C,12.01,5103.16,4000.16,2260,719.01
Phosphorus,15,P,30.98
Gallium,31,Ga,69.72,2510.16,302.96,5910,,5.61
Niobium,41,Nb,92.91,3573.16,2741.16,8400,,26.8
Hydrogen has values for all the fields.
Carbon does not have a value for Fusion
Phosphorus only has the first four values.
Gallium is missing the value for Vapour (as is Niobium)
First I just checked how many fields are in each line using the following code.
try (Scanner scan = new Scanner(new FileReader("elements2.csv"))) {
scan.nextLine(); // skip first line
int counter = 0;
while (scan.hasNextLine()) {
String line = scan.nextLine();
counter++;
String[] readFile = line.split(",");
System.out.printf("%d. [%d] ^%s^%n", counter, readFile.length, line);
}
}
catch (IOException xIo) {
throw new ExceptionInInitializerError(xIo);
}
Note that the code uses try-with-resources that was added in Java 7.
The above code produced the following output for my "sample" file.
(I use ^ to help me see if there is any leading or trailing whitespace in the string or if it is an empty string.)
1. [9] ^Hydrogen,1,H,1.01,20.46,13.96,71,0.45,0.06^
2. [8] ^Carbon,6,C,12.01,5103.16,4000.16,2260,719.01^
3. [4] ^Phosphorus,15,P,30.98^
4. [9] ^Gallium,31,Ga,69.72,2510.16,302.96,5910,,5.61^
5. [9] ^Niobium,41,Nb,92.91,3573.16,2741.16,8400,,26.8^
So now that I have an idea of what to expect, I can write the code (for class DAO) to read and parse the CSV file. The code includes handling unexpected values.
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class DAO {
private static final int ELEMENT = 0;
private static final int NUMBER = 1;
private static final int SYMBOL = 2;
private static final int WEIGHT = 3;
private static final int BOIL = 4;
private static final int MELT = 5;
private static final int DENSITY = 6;
private static final int VAPOUR = 7;
private static final int FUSION = 8;
public static List<ChemicalElement> elements = new ArrayList<>();
static {
try (Scanner scan = new Scanner(new FileReader("elements2.csv"))) {
scan.nextLine(); // skip first line
String element;
int number;
String symbol;
double weight;
double boil;
double melt;
double density;
double vapour;
double fusion;
while (scan.hasNextLine()) {
String line = scan.nextLine();
String[] readFile = line.split(",");
if (readFile.length > ELEMENT &&
readFile[ELEMENT] != null &&
!readFile[ELEMENT].isEmpty()) {
element = readFile[ELEMENT];
}
else {
element = ""; // value to use when the CSV file does not contain a value
}
if (readFile.length > NUMBER &&
readFile[NUMBER] != null &&
!readFile[NUMBER].isEmpty()) {
try {
number = Integer.parseInt(readFile[NUMBER]);
}
catch (NumberFormatException xNumberFormat) {
number = 0; // value to use if value in CSV file is missing or invalid
}
}
else {
number = 0;
}
if (readFile.length > SYMBOL &&
readFile[SYMBOL] != null &&
!readFile[SYMBOL].isEmpty()) {
symbol = readFile[SYMBOL];
}
else {
symbol = "";
}
if (readFile.length > WEIGHT) {
weight = extractDoubleValue(readFile[WEIGHT], 0.0d);
}
else {
weight = 0.0d;
}
if (readFile.length > BOIL) {
boil = extractDoubleValue(readFile[BOIL], 0.0d);
}
else {
boil = 0.0d;
}
if (readFile.length > MELT) {
melt = extractDoubleValue(readFile[MELT], 0.0d);
}
else {
melt = 0.0d;
}
if (readFile.length > DENSITY) {
density = extractDoubleValue(readFile[DENSITY], 0.0d);
}
else {
density = 0.0d;
}
if (readFile.length > VAPOUR) {
vapour = extractDoubleValue(readFile[VAPOUR], 0.0d);
}
else {
vapour = 0.0d;
}
if (readFile.length > FUSION) {
fusion = extractDoubleValue(readFile[FUSION], 0.0d);
}
else {
fusion = 0.0d;
}
ChemicalElement elem = new ChemicalElement(element,
number,
symbol,
weight,
boil,
melt,
density,
vapour,
fusion);
elements.add(elem);
}
}
catch (IOException xIo) {
throw new ExceptionInInitializerError(xIo);
}
}
public static void periodicTable() {
for (ChemicalElement element : elements) {
System.out.println(element);
}
}
private static double extractDoubleValue(String raw, double defaultValue) {
double value;
try {
value = Double.parseDouble(raw);
}
catch (NullPointerException | NumberFormatException x) {
value = defaultValue;
}
return value;
}
}
In my program I am working on converting from infix to postfix. I have a method named isOperator(), which will return true if the precedance of the operator is greater than 0.
I am supposed to rewrite the toPostfix() method using isOperator(), but I am unsure where to begin.
public class Expression {
private static final String SPACE = " ";
private static final String PLUS = "+";
private static final String MINUS = "-";
public static int rank(String operator) {
switch (operator) {
case "*":
case "/":
return 2;
case PLUS:
case MINUS: //2
return 1;
default:
return -1;
}
}
public static boolean isOperator(String token) { //4
if (rank(token) > 0){
return true;
}
return false;
}
public static String toPostfix(String infixExpr) {
StringBuilder output = new StringBuilder();
Stack<String> operators = new ArrayStack<>();
for (String token: infixExpr.split("\\s+")) {
if (rank(token) > 0) { // operator
// pop equal or higher precedence
while (!operators.isEmpty() &&
rank(operators.peek()) >= rank(token)) {
output.append(operators.pop() + SPACE);
}
operators.push(token);
} else { // operand
output.append(token + SPACE);
}
}
while (!operators.isEmpty()) {
output.append(operators.pop() + SPACE);
}
return output.toString();
}
public static void main(String[] args) {
System.out.println(rank("/"));
String infix = "a * b * c + d / e / f";
System.out.println(toPostfix(infix));
}
}
Change if(rank(token) > 0){ in your postfix method to isOperator(token)
Change: if(rank(token) > 0){
To: isOperator(token)
I'm trying to implement this pseudo-code in java, to evaluate an arithmetic expression. But I keep getting the last digit: ie if i do 1+2, i'd just get 2; I don't know what I'm doing incorrectly, so If anyone has any idea, please let me know!!
Algorithm here
import java.util.Stack;
public class Main {
static Stack<String> ops = new Stack<String>();
static Stack<Double> vals = new Stack<Double>();
private static void doOP() {
double x = vals.pop();
double y = vals.pop();
String op = ops.pop();
double v = 0;
if (op.equals("+")) {
v = y + x;
} else {
if (op.equals("-")) {
v = y - x;
} else {
if (op.equals("*")) {
v = y * x;
} else {
if (op.equals("/")) {
v = y / x;
}
}
}
}
vals.push(v);
}
private static void repeatOps(String refOp) {
while ((vals.size() > 1) && (prec(refOp) <= prec(ops.peek()))) {
doOP();
}
}
private static int prec(String refOp) {
String[] bodmas = new String[] { "(", ")", "/", "*", "+", "-", "$" };
int i = 0;
for (String operation : bodmas) {
if (refOp.equals(operation)) {
return i;
}
i++;
}
return -0;
}
private static boolean isNumber(String number) {
try {
#SuppressWarnings("unused")
double d = Double.parseDouble(number);
} catch (Exception e) {
return false;
}
return true;
}
private static Double evalExp(String exp) {
for (char z : exp.toCharArray()) {
if (isNumber(z + "")) {
vals.push(Double.parseDouble(z + ""));
} else {
repeatOps(z + "");
ops.push(z + "");
}
}
repeatOps("$");
return vals.peek();
}
public static void main(String[] args) {
System.out.println(evalExp("3*2"));
}
}
Your prec() method is inverted and incorrect.
$ should be lowest precedence, meaning lowest value, e.g. 0.
+ and - should have same precedence.
* and / should have same precedence.
( and ) are not binary operators, and cannot be handled with the described logic.
So, fix prec to return 0 for $, 1 for + and -, and 2 for * and /.
I just finished programming a calculator that performs the four basic arithmetic operations, plus six trigonometric operations, in an interface so minimalistic that it just lets the user enter the expression and displays the result, with no need for separate input of operands and operator.
I think it saves time for the user and would look more finished, for lack of a better word, if it would only work.
import java.util.*;
public class Calculator
{
public static String getOperator(String expression)
{
int counter=0;
for (int i=0; i<3; i++)
{
if (Character.isLetter(expression.charAt(i)))
counter++;
}
if (counter==3)
return expression.substring(0, 3);
else
{
for (int j=0; j<expression.length(); j++)
{
if (Character.isDigit(expression.charAt(j))==false)
{
if (expression.charAt(j)!='.')
return Character.toString(expression.charAt(j));
}
}
}
return "false";
}
public static double getFirstOperand(String operator, String expression)
{
return Double.parseDouble(expression.substring(expression.indexOf(operator)+1));
}
public static String getOperatorType(String expression)
{
int counter=0;
for (int i=0; i<3; i++)
{
if (Character.isLetter(expression.charAt(i)))
counter++;
}
if (counter==3)
return "Trigonometrical";
else
return "Arithemtic";
}
public static double getResult(String operator, double operand)
{
if (operator.equals("sin"))
return Math.sin(operand);
if (operator.equals("cos"))
return Math.cos(operand);
if (operator.equals("tan"))
return Math.tan(operand);
if (operator.equals("cot"))
return 1/Math.tan(operand);
if (operator.equals("cosec"))
return 1/Math.sin(operand);
else
return 1/Math.cos(operand);
}
public static double getSecondOperand(String expression)
{
return Double.parseDouble(expression.substring(0, expression.indexOf(expression)));
}
public static double getResult(String operator, double operand1, double operand2)
{
if (operator.equals("*"))
return operand1*operand2;
if (operator.equals("+"))
return operand1+operand2;
if (operator.equals("/"))
return operand2/operand1;
else
return operand2-operand1;
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String command="", operator="", operatorType="";
double operand1=0.0, operand2=0.0, result=0.0;
while (command.equals("EXIT")=false)
{
System.out.println("Enter command: ");
command = sc.next();
operator = getOperator(command);
operand1 = getFirstOperand(operator, command);
operatorType = getOperatorType(command);
if (operatorType.equals("Trigonometrical"))
result=getResult(operator, operand1);
if (operatorType.equals("Arithmetic"))
{
operand2 = getSecondOperand(command);
result=getResult(operator, operand1, operand2);
}
System.out.println("Result="+result);
}
}
}
Somehow, whatever I input, the result is always 0.0.
Enter command:
45*2
Result=0.0
Enter command:
2+2
Result=0.0
I don't understand where the problem is. I've searched through the code tens of times, but I just don't see it.
UPDATE: Thanks for all your help, guys. The calculator finally works as it should. In fact, nearly all the problems were caused by a single lethal error in getSecondOperand. I've fixed the code now and the repaired code is given below.
You have a typo in "Arithmetic" in getOperatorType():
public static String getOperatorType(String expression)
{
int counter=0;
for (int i=0; i<3; i++)
{
if (Character.isLetter(expression.charAt(i)))
counter++;
}
if (counter==3)
return "Trigonometrical";
else
return "Arithemtic";
}
This is why you should avoid Strings for such cases, and favor Enums instead.
Furthermore, you're comparing Strings using ==, which won't work. Use equals() instead. Or, use Enums instead.
Here's the solution:
import java.util.*;
public class Calculator
{
public static String getOperator(String expression)
{
int counter=0;
for (int i=0; i<3; i++)
{
if (Character.isLetter(expression.charAt(i)))
counter++;
}
if (counter==3)
return expression.substring(0, 3);
else
{
for (int j=0; j<expression.length(); j++)
{
if (Character.isDigit(expression.charAt(j))==false)
return Character.toString(expression.charAt(j));
}
}
return "false";
}
public static double getFirstOperand(String operator, String expression)
{
return Double.parseDouble(expression.substring(expression.lastIndexOf(operator)+1));
}
public static String getOperatorType(String expression)
{
int counter=0;
for (int i=0; i<3; i++)
{
if (Character.isLetter(expression.charAt(i)))
counter++;
}
if (counter==3)
return "Trigonometrical";
else
return "Arithmetic";
}
public static double getResult(String operator, double operand)
{
if (operator.equals("sin"))
return Math.sin(operand);
if (operator.equals("cos"))
return Math.cos(operand);
if (operator.equals("tan"))
return Math.tan(operand);
if (operator.equals("cot"))
return 1/Math.tan(operand);
if (operator.equals("cosec"))
return 1/Math.sin(operand);
else
return 1/Math.cos(operand);
}
public static double getSecondOperand(String expression, String operator)
{
return Double.parseDouble(expression.substring(0, expression.indexOf(operator)));
}
public static double getResult(String operator, double operand1, double operand2)
{
if (operator.equals("*"))
return operand1*operand2;
if (operator.equals("+"))
return operand1+operand2;
if (operator.equals("/"))
return operand2/operand1;
else
return operand2-operand1;
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String command="", operator="", operatorType="";
double operand1=0.0, operand2=0.0, result=0.0;
char exitNow='0';
while (exitNow=='0'||exitNow=='N')
{
System.out.println("Enter command: ");
command = sc.next();
operator = getOperator(command);
operand1 = getFirstOperand(operator, command);
operatorType = getOperatorType(command);
if (operatorType.equals("Trigonometrical"))
result=getResult(operator, operand1);
if (operatorType.equals("Arithmetic"))
{
operand2 = getSecondOperand(command, operator);
result=getResult(operator, operand1, operand2);
}
System.out.println("Result="+result+"\nExit now(1/0)(Y/N)");
exitNow=sc.next().charAt(0);
}
}
}
I need to make a simple calculator. I am having trouble with entering any amount of operators and operands, then outputting the answer when the equals button has been entered.
So far, if I just press one number and a digit it exits but does not give me an answer. If I do more than one operator and operand then = it does not exit the loop.
For example it should be like:
5
+
5
+
5
=
15
Here is my code, Calculator:
public interface Calculator {
public void setOperator(char operator); // eg +-*/=
public void setOperand (double operand); // eg 123.456
public double getResult();
}
SimpleCalculator:
import java.io.*;
public class SimpleCalculator implements Calculator {
char operator;
double operand;
double result;
double answer;
public void setOperator(char operator){
this.operator = operator;
}
public char getOperator(){
return operator;
}
public void setOperand(double operand){
this.operand = operand;
}
public double getOperand(){
return operand;
}
public double getResult(){
if (getOperator() == '+'){
result = (getOperand() + getOperand());
}
if (getOperator() == '-'){
result = (getOperand() - getOperand());
}
if (getOperator() == '*'){
result = (getOperand() * getOperand());
}
if (getOperator() == '/')
{
result = (getOperand() / getOperand());
}
if (getOperator() == '=')
result = answer;
}
return result;
}
public boolean getanswer(String value)
{
boolean isnum = false;
try {
setOperand(Double.parseDouble(value));
operand = (Double.parseDouble(value));
getResult();
isnum = true;
}
catch(Exception e)
{
try {
setOperator(value.charAt(0));
operator = (value.charAt(0));
isnum = false;
}
catch(Exception e2)
{
{
System.out.println("Enter a number");
}
}
return isnum;
}
}
SimpleTest:
import java.io.*;
public class SimpleTest{
static String value;
static double operand;
static char operator;
static boolean isnum;
public static void main(String[] argv){
SimpleCalculator calculator = new SimpleCalculator();
value = UserInput.readString();
while (!(value.equals("=")))
{
isnum = calculator.getanswer(value);
if (!(isnum == true))
{
break;
}
}
System.out.println(calculator.getResult());
}
}
Based on the title of your question I found that you might see an issue with your main-loop:
value = UserInput.readString();
while (!(value.equals("="))) {
isnum = calculator.getanswer(value);
if (!(isnum == true)) {
break;
}
}
Since you read the user input outside the loop it will never change and this will either run only once (if isnum is false) or infinitely (if isnum is true) -- getanswer does not has a memory with respect to its result. Thus if you input a number it will loop forever but not doing anything useful.
Please note: this is just a first guess. I didn't check the rest of your program.
You didn't really say what your problem is, but I found one for you:
You are using
result = (getOperand() + getOperand();
(and similar) to calculate your results. But getOperand() always returns the same result (since you can't execute setOperand() between these calls), so you are always adding, subtracting, multiplying and dividing the same number.