Program looks for correct balance of ( [ and { in expression I'm still new to programming. (First exposure was school about a year ago), and for some reason this problem really gave me a lot of problems trying to solve it. Can you help me understand what I could have done different/better here?

import java.util.*;
public class Lab10 {
    public static void main(String[] args) throws Exception {
        Stack&lt;String&gt; stack = new Stack&lt;&gt;();

        Scanner input = new Scanner(System.in);
        System.out.print("Enter string: ");
        String s = input.nextLine();
        input.close();      
        StringTokenizer tokens = new StringTokenizer(s, "[] () {}", true);      

        while (tokens.hasMoreTokens()) {
            String token = tokens.nextToken().trim();
            //Push opening delimeter to stack
            if (token.compareTo("(") == 0 || token.compareTo("{") == 0 ||
                    token.compareTo("[") == 0) {
                stack.push(token);
            }

            //when closing delimiter is encountered pop the stack
            else if (token.compareTo(")") == 0 || token.compareTo("}") == 0  ||
                    token.compareTo("]") == 0) {
                String popped = stack.pop();
                //make sure that there is a corresponding closing delimiter   for every opening
                if (!stack.isEmpty());              
                if (token.compareTo(")") == 0 &amp;&amp; popped.compareTo("(") != 0 ||
                    token.compareTo("}") == 0 &amp;&amp; popped.compareTo("{") != 0 ||
                    token.compareTo("]") == 0 &amp;&amp; popped.compareTo("[") != 0)   {
                    System.out.println("Incorrect grouping pairs.");
                    break;                  
                }
                //if stack is empty that means every thing was correct
                else if (stack.isEmpty()){
                    System.out.println("Correct grouping pairs.");
                }

            }           
        }       
    }
}
if (!stack.isEmpty()); 


This statement does absolutely nothing. You should remove it.

else if (stack.isEmpty()){
    System.out.println("Correct grouping pairs.");
}


Just because you removed the last pair does not mean you're done. Take, for instance, this line of code:

int x = getArray(getArrayID())[[0];


Your program first says Correct grouping pairs, before complaining about the "[[ ]" not being correctly balanced.

Next, your program is hardcoded to check for (), {} and []. But what if we wanted to add &lt;&gt;? Then you'd have a problem, because you'd need to change the code in a lot of places.

My first thought of a solution for this is to use two strings, and then using indexOf to see if our token is in the string. It's not the best solution, I think, but it would work pretty well:

String leftHandTokens = "[{(&lt;";
String rightHandTokens = "]})&gt;";


Then use like so:

if(leftHandTokens.contains(token)){
   //lefthand token
} else if(rightHandTokens.contains(token)){
   //righthand token
}


Next, finding out whether the two tokens are a correct pair:

if(leftHandTokens.indexOf(popped) == rightHandTokens.indexOf(token)){


Naturally this assumes that either of them is IN the token list in the first place. Else it will say (-1 == -1) = true.

You could simplify your code a lot like that:

String leftHandTokens = "[{(&lt;";
String rightHandTokens = "]})&gt;";

while (tokens.hasMoreTokens()) {
    String token = tokens.nextToken().trim();
    //Push opening delimeter to stack
    if (leftHandTokens.contains(token)) {
        stack.push(token);
    } else if (rightHandTokens.contains(token)) {
        String popped = stack.pop();
        //make sure that there is a corresponding closing delimiter   for every opening
        if (leftHandTokens.indexOf(popped) != rightHandTokens.indexOf(token))   {
            System.out.println("Incorrect grouping pairs.");
            break;                  
        } else if (stack.isEmpty()){
            System.out.println("Correct grouping pairs.");
        }
    }           
}


I removed some of your comments, because splitting up if-elseif branches with comments makes it VERY hard to understand. You'd think that if you see a statement like this

if(condition){
    doSomething();
}

//if there was no condition, we gotta handle the thingmabob...


You'd say that the if statement is just that. But then what you do...

else {
   handleThingmabob();
}


Is throw some else at the bottom! That's scary! I'd have to read to the next statement to be sure whether there isn't anything else coming! Worst, with comments in there, the distance between if and else might be huge! If you've got something to say, say it before you start your if-statement.

But we're not entirely done. 

You currently handle outputting whether everything was correct inside your loop.

That's a bad idea.

What you'd want to do is wrap the whole thing in a function, and the moment you find a problem, you'd return false. And when you're out of tokens, you check whether the stack is empty. That way your program will run faster for faulty inputs and will be able to determine cases where you provide blah( as a string to be faulty.