Simple Stack Calculator can't give proper fractional answers - java

Im trying to fix my code which is a simple calculator in Java made using stacks and a token class. I am having an error every time I have a decimal number as an answer. For example, if I input 11/2 it will give me 1. Its an odd error and I don't know how to fix it and was wondering if someone could tell me how. Thank you for any help!
public class SimpleCalcSkeleton {
private enum TokenType {WS,LP,RP,NUM,OP};
private static class Token {
// instance variables
private String value;
private TokenType type;
// constructor
public Token(String v, TokenType t) {
this.value = v;
this.type = t;
}
// toString() is important for diagnostic output
public String toString() {
return ("[" + value + ";" + type.toString() + "]");
}
// getter or accessor methods for the instance vars or properties
// setter methods are not needed
public String getValue() {
return value;
}
public TokenType getType() {
return type;
}
}
private static TokenType getTokenType(char c) {
TokenType type=null;
if(c==' '){
type=TokenType.WS;
}
if(c=='('){
type=TokenType.LP;
}
if(c==')'){
type=TokenType.RP;
}
if((c=='+')||(c=='-')||(c=='*')||(c=='/')){
type=TokenType.OP;
}
if((c=='0')||(c=='1')||(c=='2')||(c=='3')||(c=='4')||(c=='5')||(c=='6')||(c=='7')||(c=='8')||(c=='9')){
type=TokenType.NUM;
}
return type;
}
private static int getAssoc(Token token) {
String word = token.getValue();
int number =0;
if((word.equals('+'))||(word.equals('-'))){
number=1;
}
if((word.equals('*'))||(word.equals('/'))){
number=2;
}
return number;
}
private static ArrayList<Token> parse(String s) {
if(s==null||s.length()==0){
return null;
}
ArrayList<Token> list= new ArrayList<Token>();
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
TokenType type = getTokenType(c);
String symbol= Character.toString(c);
if(type==null){
System.out.print("Error: null");
}
else if(!type.equals(TokenType.WS)){
list.add(new Token(symbol,type));
}
}
return list;
}
private static ArrayList<Token> infixToPostfix(ArrayList<Token> intokens) {
Stack astack = new Stack();
ArrayList<Token>outokens=new ArrayList<Token>();
for(int i=0;i<intokens.size();i++){
Token in= intokens.get(i);
if(in.getType()==TokenType.NUM){
outokens.add(in);
}
if(in.getType()==TokenType.LP){
astack.push(in);
}
if(in.getType()==TokenType.RP){
Token top=(Token)astack.peek();
while(top.getType()!=TokenType.LP){
astack.pop();
outokens.add(top);
top=(Token)astack.peek();
if(top.getType()==TokenType.LP){
astack.pop();
break;
}}}
if(in.getType()==TokenType.OP){
if(!astack.isEmpty()){
Token top = (Token)astack.peek();
while((top.getType()==TokenType.OP)&&(getAssoc(top)>=getAssoc(in))){
astack.pop();
outokens.add(top);
if(!astack.isEmpty())
top=(Token)astack.peek();
else break;
}}
astack.push(in);
}
}
while(!astack.isEmpty()){
Token top=(Token)astack.peek();
astack.pop();
outokens.add(top);
if(!astack.isEmpty())
top=(Token)astack.peek();
else break;
}
return outokens;
}
private static Token evalOp(Token op, Token t1, Token t2) {
String one = t1.getValue();
String two = t2.getValue();
String opener = op.getValue();
int output =0;
int first = Integer.parseInt(one);
int second = Integer.parseInt(two);
if(opener.equals("+")){
output = second+first;
}
if(opener.equals("-")){
output = second-first;
}
if(opener.equals("*")){
output = second*first;
}
if(opener.equals("/")){
output = second/first;
}
String last = Integer.toString(output);
Token total = new Token(last,TokenType.NUM);
return total;
}
private static String evalPostfix(ArrayList<Token> intokens) {
Stack right = new Stack();
for(int i=0;i<intokens.size();i++){
Token in=intokens.get(i);
if(in.getType()==TokenType.NUM)
right.push(in);
else if(in.getType()==TokenType.OP){
Token at = (Token) right.pop();
Token bat = (Token) right.pop();
Token cat = evalOp(in,at,bat);
right.push(cat);
}
}
return right.toString();
}
public static String evalExpression(String s) {
ArrayList<Token> infixtokens = parse(s);
System.out.println("\tinfix tokens: " + infixtokens);
ArrayList<Token> postfixtokens = infixToPostfix(infixtokens);
System.out.println("\tpostfix tokens: " + postfixtokens);
return evalPostfix(postfixtokens);
}
public static void commandLine() {
Scanner in = new Scanner(System.in);
while (true){
System.out.print("> ");
String word = in.nextLine();
if (word.equals("quit")) {
break;
}
else {
System.out.println(evalExpression(word));
}
}
}
}
class SimpleCalcTest {
public static void test() {
String[] inputs = {
"3*4 + 5",
"3 + 4*5",
"(1+1)*(5-2)",
"(3*4+5)*(3*3 + 4*4)"
};
for (int i=0; i<inputs.length; i++) {
String s = inputs[i];
System.out.println();
System.out.println();
System.out.println("test: input = " + s);
String r = SimpleCalcSkeleton.evalExpression(s);
System.out.println("\tresult = " + r);
}
}
public static void main(String[] args) {
SimpleCalcSkeleton.commandLine();
SimpleCalcTest.test();
}
}

Related

split strings with backtracking

I'm trying to write a code that split a spaceless string into meaningful words but when I give sentence like "arealways" it returns ['a', 'real', 'ways'] and what I want is ['are', 'always'] and my dictionary contains all this words. How can I can write a code that keep backtracking till find the best matching?
the code that returns 'a', 'real', 'ways':
splitter.java:
public class splitter {
HashMap<String, String> map = new HashMap<>();
Trie dict;
public splitter(Trie t) {
dict = t;
}
public String split(String test) {
if (dict.contains(test)) {
return (test);
} else if (map.containsKey(test)) {
return (map.get(test));
} else {
for (int i = 0; i < test.length(); i++) {
String pre = test.substring(0, i);
if (dict.contains(pre)) {
String end = test.substring(i);
String fixedEnd = split(end);
if(fixedEnd != null){
map.put(test, pre + " " + fixedEnd);
return pre + " " + fixedEnd;
}else {
}
}
}
}
map.put(test,null);
return null;
}
}
Trie.java:
public class Trie {
public static class TrieNode {
private HashMap<Character, TrieNode> charMap = new HashMap<>();
public char c;
public boolean endOWord;
public void insert(String s){
}
public boolean contains(String s){
return true;
}
}
public TrieNode root;
public Trie() {
root = new TrieNode();
}
public void insert(String s){
TrieNode p = root;
for(char c : s.toCharArray()) {
if(! p.charMap.containsKey(c)) {
TrieNode node = new TrieNode();
node.c = c;
p.charMap.put(c, node);
}
p = p.charMap.get(c);
}
p.endOWord = true;
}
public boolean contains(String s){
TrieNode p = root;
for(char c : s.toCharArray()) {
if(!p.charMap.containsKey(c)) {
return false;
}
p = p.charMap.get(c);
}
return p.endOWord;
}
public void insertDictionary(String filename) throws FileNotFoundException{
File file = new File(filename);
Scanner sc = new Scanner(file);
while(sc.hasNextLine())
insert(sc.nextLine());
}
public void insertDictionary(File file) throws FileNotFoundException{
Scanner sc = new Scanner(file);
while(sc.hasNextLine())
insert(sc.nextLine());
}
}
WordSplitter class:
public class WordSplitter {
public static void main(String[] args) throws FileNotFoundException {
String test = "arealways";
String myFile = "/Users/abc/Desktop/dictionary.txt";
Trie dict = new Trie();
dict.insertDictionary(myFile);
splitter sp = new splitter(dict);
test = sp.split(test);
if(test != null)
System.out.println(test);
else
System.out.println("No Splitting Found.");
}
}
Using the OP's split method and the implementation of Trie found in The Trie Data Structure in Java Baeldung's article, I was able to get the following results:
realways=real ways
arealways=a real ways
However, if I remove the word "real" or "a" from the dictionary, I get the following results:
realways=null
arealways=are always
Here's the entire code I used to get these results:
public class Splitter {
private static Map<String, String> map = new HashMap<>();
private Trie dict;
public Splitter(Trie t) {
dict = t;
}
/**
* #param args
*/
public static void main(String[] args) {
List<String> words = List.of("a", "always", "are", "area", "r", "way", "ways"); // The order of these words does not seem to impact the final result
String test = "arealways";
Trie t = new Trie();
for (String word : words) {
t.insert(word);
}
System.out.println(t);
Splitter splitter = new Splitter(t);
splitter.split(test);
map.entrySet().forEach(System.out::println);
}
public String split(String test) {
if (dict.find(test)) {
return (test);
} else if (map.containsKey(test)) {
return (map.get(test));
} else {
for (int i = 0; i < test.length(); i++) {
String pre = test.substring(0, i);
if (dict.find(pre)) {
String end = test.substring(i);
String fixedEnd = split(end);
if (fixedEnd != null) {
map.put(test, pre + " " + fixedEnd);
return pre + " " + fixedEnd;
} else {
}
}
}
}
map.put(test, null);
return null;
}
public static class Trie {
private TrieNode root = new TrieNode();
public boolean find(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
current = node;
}
return current.isEndOfWord();
}
public void insert(String word) {
TrieNode current = root;
for (char l : word.toCharArray()) {
current = current.getChildren().computeIfAbsent(l, c -> new TrieNode());
}
current.setEndOfWord(true);
}
#Override
public String toString() {
return toString(root);
}
/**
* #param root2
* #return
*/
private String toString(TrieNode node) {
return node.toString();
}
public static class TrieNode {
private Map<Character, TrieNode> children = new HashMap<>() ;
private String contents;
private boolean endOfWord;
public Map<Character, TrieNode> getChildren() {
return children;
}
public void setEndOfWord(boolean endOfWord) {
this.endOfWord = endOfWord;
}
public boolean isEndOfWord() {
return endOfWord;
}
#Override
public String toString() {
StringBuilder sbuff = new StringBuilder();
if (isLeaf()) {
return sbuff.toString();
}
children.entrySet().forEach(entry -> {
sbuff.append(entry.getKey() + "\n");
});
sbuff.append(" ");
return children.toString();
}
private boolean isLeaf() {
return children.isEmpty();
}
}
public void delete(String word) {
delete(root, word, 0);
}
private boolean delete(TrieNode current, String word, int index) {
if (index == word.length()) {
if (!current.isEndOfWord()) {
return false;
}
current.setEndOfWord(false);
return current.getChildren().isEmpty();
}
char ch = word.charAt(index);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
boolean shouldDeleteCurrentNode = delete(node, word, index + 1) && !node.isEndOfWord();
if (shouldDeleteCurrentNode) {
current.getChildren().remove(ch);
return current.getChildren().isEmpty();
}
return false;
}
}
}
I improved the original code by adding a toString() method to the Trie and TrieNode. Now, when I print out the Trie object "t", I get the following result:
{a={r={e={a=}}, l={w={a={y={s=}}}}}, w={a={y={s=}}}}
My conclusion is that the OP's TrieNode implementation is incorrect. The way the Trie is built, given the inputted string value, the behavior described by the OP seems to be correct.

How to compare Strings ignoring cases in Java

Newbie here I am trying to compare the brand and display to an array of Strings. Seems to be working now but I don't know how to make the comparison case-insensitive. All the options I found so far is to compare a string to another string. There is any way I can make that comparison? Right now only accept the values as stated in the array of strings.
P.S. This was an existing homework that our instructor wanted us to build on it, hence why I am using the "isValid" methods for validation.
Thanks!
import com.entertainment.Television;
import java.util.Arrays;
import java.util.Scanner;
class TelevisionConsoleClient {
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
welcomeMessage();
}
public static void welcomeMessage() {
//Welcome message to buyer
System.out.println("Welcome to Our Online Ordering System.");
System.out.println("Please answer the questions below to submit your order.");
String brand = brandChoice();
String display = displayChoice();
int size = sizeChoice();
System.out.println("Thank you. The television you ordered is: ");
television(brand, display, size);
//close scanner
scanner.close();
}
public static String brandChoice() {
String brandChoice = null;
boolean hasBrand = false;
while (!hasBrand) {
System.out.println("Please enter the desired brand " + Arrays.toString(Television.VALID_BRANDS) + ":");
brandChoice = scanner.nextLine();
if (Television.isValidBrand(brandChoice))
hasBrand = true;
else
System.out.println("Sorry " + brandChoice + " is not a valid brand");
}
return brandChoice;
}
private static String displayChoice() {
String displayChoice = null;
boolean hasDisplay = false;
while (!hasDisplay) {
System.out.println("Please enter the desired display type " + Arrays.toString(Television.VALID_DISPLAY) + ":");
displayChoice = scanner.nextLine();
if (Television.isValidDisplay(displayChoice))
hasDisplay = true;
else
System.out.println("Sorry " + displayChoice + " is not a valid display type");
}
return displayChoice;
}
private static int sizeChoice() {
Integer sizeChoice = null;
boolean hasSize = false;
while (!hasSize) {
System.out.println("Please enter the desired size " + Arrays.toString(Television.VALID_SIZES) + ":");
sizeChoice = Integer.parseInt(scanner.nextLine());
if (Television.isValidSize(sizeChoice))
hasSize = true;
else
System.out.println("Sorry " + sizeChoice + " is not a valid size");
}
return sizeChoice;
}
private static void television(String brand, String display, int size) {
System.out.println(new Television(brand, display, size));
}
}
package com.entertainment;
public class Television {
// CLASS OR STATIC VARIABLES - STORED IN THE SHARED AREA ASSOCIATED WITH A CLASS
public static final String[] VALID_BRANDS = {"Samsung", "LG", "Sony", "Toshiba"};
public static final String[] VALID_DISPLAY = {"LED", "OLED", "PLASMA", "LCD", "CRT"};
public static final int[] VALID_SIZES = {32, 40, 43, 50, 55, 60, 65, 70, 75, 80};
// FIELDS - AKA 'INSTANCE VARIABLES', 'ATTRIBUTES', 'PROPERTIES'
private String brand;
private String display;
private int size;
// CONSTRUCTORS
// No-arg constructor.
public Television() {
// possible additional "setup" or initialization code here
// want it to run for every instance created
}
// 3-arg constructor
public Television(String brand, String display, int size) {
this.brand = brand;
this.display = display;
this.size = size;
}
// ACCESSOR METHODS (getters/setters)
public String getBrand() {
return brand;
}
public String getDisplay() {
return display;
}
public int getSize() { return size; }
public static boolean isValidBrand(String brand) {
boolean isValid = false;
for (String currentBrand : VALID_BRANDS) {
if (currentBrand.equals(brand)) {
isValid = true;
break;
}
}
return isValid;
}
public static boolean isValidDisplay(String display) {
boolean isValid = false;
for (String currentDisplay : VALID_DISPLAY) {
if (currentDisplay.equals(display)) {
isValid = true;
break;
}
}
return isValid;
}
public static boolean isValidSize(int size) {
boolean isValid = false;
for (int currentSize : VALID_SIZES) {
if (currentSize == size) {
isValid = true;
break;
}
}
return isValid;
}
public String toString() {
return "Television: " + getBrand() + ", Display: " + getDisplay() + ", Size: " + getSize() + " inches.";
}
}
Change String.equals(Object) to String.equalsIgnoreCase(String). That is,
if (currentBrand.equals(brand))
if (currentDisplay.equals(display))
to
if (currentBrand.equalsIgnoreCase(brand))
if (currentDisplay.equalsIgnoreCase(display))

Why is method printing when there is no code to print

Attempting to get this output at the 2nd last part:
/*****test finalistsToFile2 with sorted arraylist*****/
/**************check file testSorted.txt**************/
/****************************************************/
However, my actual output is:
/****************************************************/
/*****test finalistsToFile2 with sorted arraylist*****/
/**************check file testSorted.txt**************/
**ID: 85011, Final Mark: 69.2, Classification: UPPER_SECOND
Candidate is BORDERLINE
ID: 62138, Final Mark: 59.9, Classification: LOWER_SECOND
Candidate is BORDERLINE**
/****************************************************/
I've attempted debugging but still cannot find the root cause of the extra 4 lines of printing under 'check file testSorted.txt' (in bold). Any idea what I can do? I have a total of 3 classes used as shown below:
ProcessDegreeMark class
import java.util.*;
import java.io.*;
public class ProcessDegreeMark{
private ProcessDegreeMark() {}
public static ArrayList<Finalist> finalistsInList(String s) throws Exception{
ArrayList<Finalist> finalists = new ArrayList<Finalist>();
String id;
double mark;
Scanner in = null;
try
{
in = new Scanner(new FileReader(s));
try
{
while(in.hasNextLine())
{
id =in.nextLine();
mark = Double.parseDouble(in.nextLine());
finalists.add(new Finalist(id,mark));
}
}
finally
{
in.close();
}
}
catch(IOException e)
{
System.out.println(s+" not found");
}
return finalists;
}
public static void displayFinalists(ArrayList<Finalist> finalists){
for (int i = 0; i < finalists.size(); i++)
{
System.out.println(finalists.get(i));
}
}
public static void findFinalistID(ArrayList<Finalist> a, String s){
int count =0;
for (int i=1;i<a.size();i++)
{
if (((a.get(i))).getId().equals(s))
{
System.out.println(a.get(i));
count++;
}
}
if(count==0)
{
System.out.println("No candidate found with ID number "+s);
}
}
public static void findFinalistClass(ArrayList<Finalist> a, String s){
int count =0;
for (int i=1;i<a.size();i++)
{
if (((a.get(i))).getdegreeClass().equals(s))
{
System.out.println(a.get(i));
count++;
}
}
if(count==0)
{
System.out.println("No candidate found with degree class "+s);
}
}
public static ArrayList<Finalist> sortDegreeMark(ArrayList<Finalist> a){
ArrayList<Finalist> sortedFinalists = new ArrayList<Finalist>();
sortedFinalists.addAll(a);
Collections.sort(sortedFinalists, new FinalistComparator());
return sortedFinalists;
}
public static void finalistsToFile2(ArrayList<Finalist> finalists, String s) {
try
{
PrintStream out = new PrintStream(new FileOutputStream(s));
try
{
for(int i = 0; i < finalists.size(); i++)
{
out.println(finalists.get(i));
}
}
finally
{
out.close();
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
public static void findAndSaveFinalistClass(ArrayList<Finalist> a, String s){
ArrayList<Finalist> searchFinalists = new ArrayList<Finalist>();
int count =0;
for (int i=1;i<a.size();i++)
{
if (((a.get(i))).getdegreeClass().equals(s))
{
System.out.println(a.get(i));
searchFinalists.add(a.get(i));
finalistsToFile2(searchFinalists,"testSorted.txt");
count++;
}
}
if(count==0)
{
System.out.println("No candidate found with degree class "+s);
}
}
public static void main(String[] args) throws Exception{
System.out.println("/****************************************************/");
System.out.println("/*******finalistsInList with invalid file name*******/");
System.out.println();
ArrayList<Finalist> testList = finalistsInList("file***.txt");
System.out.println();
System.out.println("/****************************************************/");
System.out.println("/********finalistsInList with valid file name********/");
System.out.println("/********display to check arraylist populated********/");
System.out.println();
ArrayList<Finalist> finalists = finalistsInList("finalMark.txt");
displayFinalists(finalists);
System.out.println();
System.out.println("/****************************************************/");
System.out.println("/*testing findFinalistID with valid and invalid data*/");
System.out.println();
findFinalistID(finalists, "75021");
findFinalistID(finalists, "21050");
System.out.println();
System.out.println("/****************************************************/");
System.out.println("/*test findFinalistClass with valid and invalid data*/");
System.out.println();
findFinalistClass(finalists, "FIRST");
findFinalistClass(finalists, "THIRD");
System.out.println();
System.out.println("/****************************************************/");
System.out.println("/*****run sortedFinalists then test with display*****/");
System.out.println();
ArrayList<Finalist> sortedFinalists = sortDegreeMark(finalists);
displayFinalists(sortedFinalists);
System.out.println();
System.out.println("/****************************************************/");
System.out.println("/*****test finalistsToFile2 with sorted arraylist*****/");
System.out.println("/**************check file testSorted.txt**************/");
System.out.println();
finalistsToFile2(sortedFinalists, "testSorted.txt"); //save the sorted arraylist to a new file, check by opening file
System.out.println();
System.out.println("/****************************************************/");
System.out.println("/*test findAndSaveFinalistClass with valid and invalid data*/");
System.out.println();
findAndSaveFinalistClass(finalists, "FIRST"); //test method finds
findAndSaveFinalistClass(finalists, "THRID"); //check appropriate error message when nothing found, open new text file
System.out.println();
System.out.println("/*********************THE END************************/");
}
}
Finalist class
public class Finalist{
private String id;
private double degreeMark;
private String degreeClass;
private boolean borderline;
public Finalist(String id, double degreeMark) {
this.id = id;
this.degreeMark = degreeMark;
borderline = calcBorderline();
degreeClass = assignDegreeClass();
}
private String assignDegreeClass(){//change method name
if (degreeMark<40) return "FAIL";
if (degreeMark<50) return "THIRD";
if (degreeMark<60) return "LOWER_SECOND";
if (degreeMark<70) return "UPPER_SECOND";
return "FIRST";
}
private boolean calcBorderline(){
double x;
if (degreeMark<40){
x = 40.0-degreeMark;
if (x < 1.0) return true;
}
if (degreeMark<50){
x = 50.0-degreeMark;
if (x < 1.0) return true;
}
if (degreeMark<60){
x = 60.0-degreeMark;
if (x < 1.0) return true;
}
if (degreeMark<70){
x = 70.0-degreeMark;
if (x < 1.0) return true;
}
return false;
}
public String getId(){
return id;
}
public double getDegreeMark(){
return degreeMark;
}
public String getdegreeClass(){
return degreeClass;
}
public boolean getborderline(){
return borderline;
}
public String toString() {
String s = "ID: " + id + ", Final Mark: " + degreeMark + ", Classification: " + degreeClass + System.lineSeparator();
if(calcBorderline()==true)
{
System.out.print(s);
System.out.println("Candidate is BORDERLINE");
}
else if(calcBorderline()==false)
{
return s;
}
return "";
}
}
FinalistComparator class
import java.util.Comparator;
//sort by degree mark, descending
class FinalistComparator implements Comparator<Finalist> {
#Override
public int compare(Finalist f1, Finalist f2) {
int degreeComparisonResult = Double.compare(f2.getDegreeMark(),f1.getDegreeMark());
return degreeComparisonResult;
}
}
The unexpected output is performed in Finalist.toString() because of out.println(finalists.get(i));. Since PrintStream.println(Object x) calls toString() of the provided Object.
Update: since you stated that you need the second line: Candidate is BORDERLINE just add it to the return value and don't directly print it on System.out else you will get unexpected outputs.
#Override
public String toString() {
String s = "ID: " + id + ", Final Mark: " + degreeMark + ", Classification: " + degreeClass + System.lineSeparator();
if(calcBorderline()) {
s += "Candidate is BORDERLINE" + System.lineSeparator();
}
return s;
}
Original answer:
So avoid the use of System.out.println() in toString(), i would recommand to keep it as simple as possible and put logic in another method.
For example:
public class Finalist{
/* all the other code */
#Override
public String toString() {
return "ID: " + id + ", Final Mark: " + degreeMark + ", Classification: " + degreeClass;
}
}
public class ProcessDegreeMark {
/** Writes all non BORDERLINE candidates in the file and outputs the skipped finalists to System.out */
public static void saveToFileWithoutBorderline(List<Finalist> list, File file) {
try (PrintStream out = new PrintStream(new FileOutputStream(file))){
for(Finalist finalist : list) {
if(finalist.calcBorderline()) {
System.out.println("Skip BORDERLINE candidate: "+finalist.toString());
} else {
out.println(finalist.toString());
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
I only provided a sample code to skip the borderline candidates in saveToFile, since I didn't know where you have to skip or suppress them.

Reduce code duplication when reading different types of numbers from console

I have created three methods readLong, readInt and readDouble that basically does the same thing. Only difference is the method called by a scanner. How can I reduce duplicate code by turning them all to one method?
public long readLong(String description)
{
System.out.println(description);
long nrToReturn = 0;
boolean acceptedValue = false;
do {
System.out.println();
System.out.print("Choose one: ");
try
{
nrToReturn = consoleScanner.nextLong(); //Only line thats different except return value
acceptedValue = true;
}catch(Exception e)
{
acceptedValue = false;
consoleScanner.nextLine();
}
}while (!acceptedValue);
consoleScanner.nextLine();
return nrToReturn;
}
Here we go with one idea:
import java.util.Scanner;
public class ScannerTest {
private Scanner consoleScanner;
public ScannerTest() {
consoleScanner = new Scanner(System.in);
}
#SuppressWarnings("unchecked")
private <T extends Number> T readType(String description, Class<T> desiredType) {
System.out.println(description);
Number result = null;
while (result == null) {
System.out.println();
System.out.print("Choose one: ");
try {
if (Integer.class.equals(desiredType)) {
result = new Integer(consoleScanner.nextInt());
} else if (Long.class.equals(desiredType)) {
result = new Long(consoleScanner.nextLong());
}
} catch(Exception e) {
consoleScanner.nextLine();
}
}
consoleScanner.nextLine();
return (T) result;
}
public long readLong(String description) {
return this.readType(description, Long.class);
}
public int readInt(String description) {
return this.readType(description, Integer.class);
}
public static void main(String[] args) {
ScannerTest t = new ScannerTest();
t.readLong("Reading a long value...");
t.readInt("Reading an integer value...");
}
}
Update, following #Michu93 idea of a single transparent method:
import java.util.Scanner;
public class ScannerTest {
private Scanner consoleScanner;
public ScannerTest() {
consoleScanner = new Scanner(System.in);
}
#SuppressWarnings("unchecked")
public <T extends Number> T readNumber(String description) {
System.out.println(description);
Number result = null;
while (result == null) {
System.out.print("\nChoose one: ");
String textRead = consoleScanner.next();
try {
result = new Integer(textRead);
} catch(Exception e1) {
try {
result = new Long(textRead);
} catch (Exception e2) {
try {
result = new Double(textRead);
} catch (Exception e3) {
}
}
}
consoleScanner.nextLine();
}
return (T) result;
}
public static void main(String[] args) {
ScannerTest t = new ScannerTest();
for (int i = 0; i < 3; i++) {
Number input = t.readNumber(i + ": Reading int, long or double...");
System.out.println("Input class: " + input.getClass().getCanonicalName());
System.out.println("Input value: " + input);
}
}
}

I am changing a part of an object but it keeps changing all objects in the list without considering the condition set

I am trying to set period number 1 of every Monday of every CourseGroup to true but the object changes all the days instead of only Mondays.Kindly checkout the example below
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
class HelloWorld {
public static void main(String[] args) {
SchoolObject schoolObject;
List<LecturePeriod> lecturePeriods = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
String periodName = "Period " + i;
int periodNo = i;
boolean isPeriodAllocated = false;
lecturePeriods.add(new LecturePeriod(periodName, periodNo, isPeriodAllocated));
}
List<Day> days = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
String dayName;
switch (i) {
case 1:
dayName = "MONDAY";
break;
case 2:
dayName = "TUESDAY";
break;
case 3:
dayName = "WEDNESDAY";
break;
case 4:
dayName = "THURSDAY";
break;
case 5:
dayName = "FRIDAY";
break;
default:
dayName = "NONE";
}
int dayNo = i;
days.add(new Day(dayName, dayNo, lecturePeriods));
}
List<YearGroup> yearGroups = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
int yearGroupNumber = i;
if (Objects.equals(i, 1)) {
yearGroups.add(new YearGroup(yearGroupNumber, new ArrayList<>(Arrays.asList(new CourseGroup("Science" + 1, days)))));
} else if (Objects.equals(i, 2)) {
yearGroups.add(new YearGroup(yearGroupNumber, new ArrayList<>(Arrays.asList(new CourseGroup("Science" + 2, days)))));
} else if (Objects.equals(i, 3)) {
yearGroups.add(new YearGroup(yearGroupNumber, new ArrayList<>(Arrays.asList(new CourseGroup("Science" + 3, days)))));
}
}
schoolObject = new SchoolObject();
schoolObject.setYearGroups(yearGroups);
System.out.println("School Object Before Changing Periods="+schoolObject.toString());
schoolObject.getYearGroups().forEach(yearGroup -> {
yearGroup.getCourseGroups().forEach(courseGroup -> {
courseGroup.getDays().forEach(day -> {
String dayName = day.getDayName();
if (Objects.equals(dayName, "MONDAY")) {
day.getLecturePeriods().forEach(lecturePeriod -> {
int lecturePeriodNumber = lecturePeriod.getPeriodNumber();
if (Objects.equals(lecturePeriodNumber, 1)) {
lecturePeriod.setIsPeriodAllocated(true);
}
});
}
});
});
});
System.out.println("\nSchool Object After Changing Periods=" + schoolObject.toString());
final int[] numberOfAllocatedPeriodsExpected = {0};
schoolObject.getYearGroups().forEach(yearGroup -> {
yearGroup.getCourseGroups().forEach(courseGroup -> {
courseGroup.getDays().forEach(day -> {
day.getLecturePeriods().forEach(lecturePeriod -> {
int lecturePeriodNumber = lecturePeriod.getPeriodNumber();
if (Objects.equals(lecturePeriodNumber, 1)) {
numberOfAllocatedPeriodsExpected[0]++;
}
});
});
});
});
System.out.println("\nTest result ="+Objects.equals(numberOfAllocatedPeriodsExpected[0],3));
}
public static class SchoolObject {
List<YearGroup> yearGroups;
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("SchoolObject{");
sb.append("yearGroups=").append(yearGroups);
sb.append('}');
return sb.toString();
}
public List<YearGroup> getYearGroups() {
return yearGroups;
}
public void setYearGroups(List<YearGroup> yearGroups) {
this.yearGroups = yearGroups;
}
}
public static class YearGroup {
int yearGroupNumber;
List<CourseGroup> courseGroups;
public YearGroup(int yearGroupNumber, List<CourseGroup> courseGroups) {
this.yearGroupNumber = yearGroupNumber;
this.courseGroups = courseGroups;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("YearGroup{");
sb.append("yearGroupNumber=").append(yearGroupNumber);
sb.append(", courseGroups=").append(courseGroups);
sb.append('}');
return sb.toString();
}
public int getYearGroupNumber() {
return yearGroupNumber;
}
public void setYearGroupNumber(int yearGroupNumber) {
this.yearGroupNumber = yearGroupNumber;
}
public List<CourseGroup> getCourseGroups() {
return courseGroups;
}
public void setCourseGroups(List<CourseGroup> courseGroups) {
this.courseGroups = courseGroups;
}
}
public static class CourseGroup {
String courseGroupName;
List<Day> days;
public CourseGroup(String courseGroupName, List<Day> days) {
this.courseGroupName = courseGroupName;
this.days = days;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("CourseGroup{");
sb.append("courseGroupName='").append(courseGroupName).append('\'');
sb.append(", days=").append(days);
sb.append('}');
return sb.toString();
}
public List<Day> getDays() {
return days;
}
public void setDays(List<Day> days) {
this.days = days;
}
public String getCourseGroupName() {
return courseGroupName;
}
public void setCourseGroupName(String courseGroupName) {
this.courseGroupName = courseGroupName;
}
}
public static class Day {
String dayName;
int dayNo;
List<LecturePeriod> lecturePeriods;
public Day(String dayName, int dayNo, List<LecturePeriod> lecturePeriods) {
this.dayName = dayName;
this.lecturePeriods = lecturePeriods;
this.dayNo = dayNo;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("Day{");
sb.append("dayName='").append(dayName).append('\'');
sb.append(", dayNo=").append(dayNo);
sb.append(", lecturePeriods=").append(lecturePeriods);
sb.append('}');
return sb.toString();
}
public String getDayName() {
return dayName;
}
public void setDayName(String dayName) {
this.dayName = dayName;
}
public int getDayNo() {
return dayNo;
}
public void setDayNo(int dayNo) {
this.dayNo = dayNo;
}
public List<LecturePeriod> getLecturePeriods() {
return lecturePeriods;
}
public void setLecturePeriods(List<LecturePeriod> lecturePeriods) {
this.lecturePeriods = lecturePeriods;
}
}
public static class LecturePeriod {
String periodName;
int periodNumber;
boolean isPeriodAllocated;
public LecturePeriod(String periodName, int periodNumber, boolean isPeriodAllocated) {
this.periodName = periodName;
this.periodNumber = periodNumber;
this.isPeriodAllocated = isPeriodAllocated;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("LecturePeriod{");
sb.append("periodName='").append(periodName).append('\'');
sb.append(", periodNumber=").append(periodNumber);
sb.append(", isPeriodAllocated=").append(isPeriodAllocated);
sb.append('}');
return sb.toString();
}
public String getPeriodName() {
return periodName;
}
public void setPeriodName(String periodName) {
this.periodName = periodName;
}
public int getPeriodNumber() {
return periodNumber;
}
public void setPeriodNumber(int periodNumber) {
this.periodNumber = periodNumber;
}
public boolean isPeriodAllocated() {
return isPeriodAllocated;
}
public void setIsPeriodAllocated(boolean isPeriodAllocated) {
this.isPeriodAllocated = isPeriodAllocated;
}
}
}
Observing the output of the data,you notice that the schoolObject set all lecturePeriods to true for all days in each courseGroup instead of only Mondays.
Any help will be much appreciated.
Note:I tried my best to extract the problem to the barest minimum without using gson or jackson which would have allowed a cleaner output when combing through the json generated.
For testing sake,I cramped everything into one class.
You can check the sample here http://ideone.com/3uyE5G
This is because you are assigning the same reference of lecture periods for all days:
days.add(new Day(dayName, dayNo, lecturePeriods));
Because of this, everytime you change a property in the lecturePeriods object in one of the days it will change for all of them. To solve this issue, each day has to have it's own instance of lecturePeriods
List<LecturePeriod> lecturePeriods = new ArrayList<>();
for (int j = 1; j <= 10; j++) {
lecturePeriods.add(new LecturePeriod("Period " + j, j, false));
}
days.add(new Day(dayName, dayNo, lecturePeriods));
#valarauko,what you showed me was perfectly true,each day had to have it's own instance of lecturePeriods,but a more scalable solution I found was that,since the object could have been initialized in a different number of ways,what I did was
1.Convert the Object into a json String .
2.Convert it back to the original Object before any manipulation.
I used gson for the above two steps and it works perfectly,regardless of how I initialized each day in the schoolObject.
So thanks once again for showing me the root cause #valarauko.

Categories