Explain the working of Java postfix calculator.

268    Asked by DylanPowell in Java , Asked on Oct 13, 2022
 I made a postfix calculator in Java.
The code performs the functions I planned without problems, However, I'm not satisfied with it, because it's too verbose and I couldn't split it up into methods properly, especially PostfixCalculator.changeNotation().
Any help would be greatly appreciated.
Main.java
public class Main 
{
    public static void main(String[] args) 
    {
        PostfixCalculator postCalc = new PostfixCalculator();
    }
}
Stack.java (I didn't use the library because I'm studying data structures.)
import java.util.ArrayList;
import java.util.Scanner;
public class Stack 
{
    Scanner scan = null;
    public ArrayList stack;
    public Stack() 
    {
        scan = new Scanner(System.in);
        stack = new ArrayList();
    }
    public boolean isEmpty() 
    {
        if (stack.size() == 0) 
        {
            return true;
        } 
        else 
        {
            return false;
        } 
    }
    public void push(String element) 
    {
        stack.add(element);
    }
    public void pop() 
    {   
        if(stack.isEmpty()) 
        {
            return;
        }
        else 
        {
            stack.remove(stack.size()-1);
        }
    }
    public int size() 
    {
        return stack.size();
    }
    public String peek() 
    {
        if (stack.isEmpty()) 
        {
            return null;
        } 
        else 
        {
            return stack.get(stack.size() - 1); 
        }
    }
}
PostfixCalculator.java
import java.util.ArrayList;
import java.util.Scanner;
public class PostfixCalculator 
{
    String[] infixNotation = null;
    String postfixNotation = "";
    ArrayList aListPostfixNotation = null;
    Scanner scan = null;
    Stack stk = null;
    public PostfixCalculator() 
    {
        aListPostfixNotation = new ArrayList();  
        stk = new Stack();
        scan = new Scanner(System.in);
        String myInput = scan.nextLine();
        infixNotation = myInput.split("",0);
        postfixCalculate(changeNotation());
    }
    public String changeNotation() // Change the entered code from infix notation to postfix notation 
    {
        for (int i = 0; i < infixNotation>        {   
            if(infixNotation[i].equals(" "))  
            {
                continue;
            }
            else if( !infixNotation[i].equals("+") &&  // when infixNotation[i] is operand
                    !infixNotation[i].equals("-") &&
                    !infixNotation[i].equals("*") &&
                    !infixNotation[i].equals("/") &&
                    !infixNotation[i].equals("(") &&
                    !infixNotation[i].equals(")") )   
            {
                postfixNotation = postfixNotation + infixNotation[i];
            }
            else  // when infixNotation[i] is operator or bracket
            {
                if(stk.isEmpty())  // It can push()ed, when stack is empty    // Don't care ")~~~", because the ")" can't be first char  
                {
                    stk.push(infixNotation[i]);
                }
                else 
                {
                    if (infixNotation[i].equals("("))   // Just push() when it's '('
                    {
                        stk.push(infixNotation[i]);
                    }
                    else if (infixNotation[i].equals(")")) // When bracket is balanced (left and right), pop() a pair of bracket
                    {
                        stk.push(infixNotation[i]);
                        whenRightPush();
                    }
                    else  // Have to the priority, when infixNotation[i] is operator 
                    {
                        if (stk.peek().equals("("))  
                        {   
                            stk.push(infixNotation[i]);
                        }
                        else 
                        {
                            if ( infixNotation[i].equals("*") || infixNotation[i].equals("/") )  
                            {
                                if ( stk.peek().equals("+") || stk.peek().equals("-") )
                                {
                                    stk.push(infixNotation[i]);
                                }
                                else if ( stk.peek().equals("*") || stk.peek().equals("/") )
                                {
                                    postfixNotation = postfixNotation + stack.peek();
                                    stk.pop();
                                    stk.push(infixNotation[i]);
                                }
                            }
                            else if ( infixNotation[i].equals("+") || infixNotation[i].equals("-") )
                            {
                                if ( stk.peek().equals("+") || stk.peek().equals("-")) 
                                    // Equal level's operators can't enter the stack twice sequentially, 
                                    // so they need to be considered only once.
                                {
                                    postfixNotation = postfixNotation + stack.peek();
                                    stk.pop();
                                    stk.push(infixNotation[i]);
                                }
                                else if ( stk.peek().equals("*") || stk.peek().equals("/") )
                                {
                                    postfixNotation = postfixNotation + stack.peek(); 
                                    stk.pop();  
                                    if ( stk.peek().equals("+") || stk.peek().equals("-") )  // ex + * -
                                    {
                                        postfixNotation = postfixNotation + stack.peek(); 
                                        stk.pop();
                                    }
                                    stk.push(infixNotation[i]);
                                }
                            }
                        }
                    }
                }
            }
            if (i == infixNotation.length-1)  // All elements is pop()ed, when 'i' have last value
            {
                while(!stk.isEmpty())  
                {
                    if(stk.peek().equals("("))  
                    {
                        stk.pop();
                    }
                    else if (stk.peek().equals(")"))  
                    {
                        stk.pop();
                    }
                    else 
                    {
                        postfixNotation = postfixNotation + stack.peek();
                        stk.pop();
                    }
                }
            }
        }
        System.out.println(postfixNotation);
        return postfixNotation; 
    }
    public void whenRightPush()  
    // This method will work when ')' is push()ed // I can't find proper name for this method
    {
        stk.pop();  
        while(true)
        {
            if ( stk.peek().equals("(") )  
            {
                stk.pop();
                break;
            }
            else  // 연산자일 경우 후위표기식 문자열에 붙인 후 pop()
            {
                postfixNotation = postfixNotation + stack.peek();
                stk.pop();
            }
        }
    }


    public void postfixCalculate(String postNotation)   // Calculate the postfix notation

    {  


        int operatorCount = 0;

        int resultTemp = 0;


        String[] arrayPostfixNotation = postNotation.split("", 0);  


        for (String str : arrayPostfixNotation)  

        {

            aListPostfixNotation.add(str);

        }


        for (String str : aListPostfixNotation)  

        {

            if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/"))

            {

                operatorCount++;

            }

        }



        while(operatorCount > 0) {  


            for(int i = 0; i < aListPostfixNotation>

            {

                if (aListPostfixNotation.get(i).equals("+") || 

                        aListPostfixNotation.get(i).equals("-") || 

                        aListPostfixNotation.get(i).equals("*") || 

                        aListPostfixNotation.get(i).equals("/"))

                {


                    if(aListPostfixNotation.get(i).equals("+"))

                    {

                        resultTemp = Integer.parseInt(aListPostfixNotation.get(i-2)) 

                                + Integer.parseInt(aListPostfixNotation.get(i-1));

                    }

                    else if(aListPostfixNotation.get(i).equals("-"))

                    {

                        resultTemp = Integer.parseInt(aListPostfixNotation.get(i-2)) 

                                - Integer.parseInt(aListPostfixNotation.get(i-1));

                    }

                    else if(aListPostfixNotation.get(i).equals("*")) 

                    {

                        resultTemp = Integer.parseInt(aListPostfixNotation.get(i-2)) 

                                * Integer.parseInt(aListPostfixNotation.get(i-1));

                    }

                    else

                    {

                        resultTemp = Integer.parseInt(aListPostfixNotation.get(i-2)) 

                                / Integer.parseInt(aListPostfixNotation.get(i-1));

                    }

                    aListPostfixNotation.remove(i-2);    // Remove the used operator and operand

                    aListPostfixNotation.remove(i-2);     

                    aListPostfixNotation.remove(i-2);    

                    aListPostfixNotation.add(i-2, Integer.toString(resultTemp));  // Add the result of operation into the arraylist


                    operatorCount--;  


                    break;


                }

            }

        }


        System.out.println(resultTemp);

    }

}


Answered by Kimberly Greene

Here are a few potential things that could be changed:


Stack.java

The isEmpty() method can be simplified, since your underlying data structure that you are using to implement a stack also exposes this method:

public boolean isEmpty()
{
    return stack.isEmpty();
}
In Java, pop() generally returns the element that was popped, while here it simply removes the element. This necessitates a peek() + pop() combination, where the convention is just pop(). There is nothing really wrong with your approach, so this is just a matter of convention.
One thing though, pop() simply returns when the stack is empty - so there is no direct indication that the operation failed. That is, if the stack is misused, it does not directly indicate it, either using some kind of Exception or by returning false on failure. Generally, pop() "convention" in Java would throw an Exception on an empty stack.
public String pop() throws StackException
{
    if(isEmpty())
        throw new StackException("pop on empty stack");
    return stack.remove(stack.size() - 1);
}
Main.java and PostfixCalculator.java
Moving the I/O work from Java Postfix Calculator class to your Main class. Ideally, the PostfixCalculator should only perform calculations and postfix related operations - getting the data to pass to it should be done elsewhere.
Therefore, the changeNotation() method could be modified to take in a String as input, rather than obtaining it itself, which ties the class to a particular input method. Deciding to read from a file or from the network rather than Standard Input should not trigger changes to the PostfixCalculator.
public String changeNotation(String infix) { ... }
In addition, it is also possible to make these methods static, since you don't really need to save any state: the calculator simply takes in an input and returns an output.
Within changeNotation():
for(int i = 0; i < infixNotation xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed>

Your Answer