1

EDIT: Recent happenings of me compiling a program I know could not compile lead me to believe I am simultaneously having an issue with my compiler. No doubt due to my running it in WINE on mac as opposed to a native application. Thank you for your responses. I will properly test out all responses and make all changes when I have fixed said error with compiler or I have moved computers to one with a working one.

I am relatively new to programming and also this website so please bear with me. I am getting an error with my two of my If statements and one do/while that I am unable to resolve.

The entire program works as intended but two blocks which are below. The problem is that when I enter the character 'y', everything works as intended and the ("Results =" + Arrays.toString(row)) prints as I expected it to. It also proceeds to continue through the original For loop and start the program again.

However, when I enter any other character, (i.e not 'y' or 'n') the code does not print "Input must be either 'y' or 'n'" and just waits for another input. Even when 'n' is entered, it does not follow out of the the loop as I wanted, it just continues to loop and not proceed to the else if I had thought it would. It does this indefinitely, not accepting any other input than 'y' to continue passed the loop so I can never receive the print "negative".

Does anyone have any thoughts as to why this is happening? While not technically homework, I tagged it as such as I want to know, if possible, what is happening as opposed to just how to fix it.

        do {
            ans = input.next().charAt(0);
                if (!ans.equals('y')  ||  !ans.equals('n')) {
                    System.out.println ("Input must be either 'y' or 'n'");
                }
        } while (!ans.equals('y')  ||  !ans.equals('n'));

and

if (ans.equals('y')) {
            for (Object[] row : prevResults) {
                    System.out.println("Results = " + Arrays.toString(row));
            }
        } //
        else if (ans.equals('n')) {
            System.out.println("Negative");
            //System.exit(0); 
        }

Full code is as below

import java.util.*;

public class Averages {
    public static void main (String [] args) {

        //declare variables
        int course, exam, average = 0;
        char ans;
        String pass;

        //creating objects
        Scanner input =  new Scanner(System.in);
        List<Object[]> prevResults = new ArrayList<Object[]>();

        //full loop
        for (int i = 0; i < 5; i++ ) {

            System.out.println ("Loop " + (++i) + " out of 5");

            //Course loop
            do {
            System.out.println ("Please enter a course mark out of 100");
            course = input.nextInt();
                if (course > 100) {
                    System.out.println ("Number entered is over 100");
                }
            } while (course > 100);

            //Exam loop
            do {
            System.out.println ("Please enter an exam mark out of 100");
            exam = input.nextInt();
                if (exam > 100) {
                    System.out.println ("Number entered is over 100");
                }
            } while (exam > 100);


            average = (course + exam)/2;

            // Final Grade
            System.out.println ("The average mark is " + average);

            if ( average >= 50 && course > 40 && exam > 40)  {
                System.out.println ("The final grade is pass");
                pass = "Pass";
            }
            else {
                System.out.println ("The final grade is fail");
                pass = "Fail";
            }

            //add to array
            prevResults.add(new Object[] { "Course mark: " + course, "Exam mark: " + exam,"Average: " + average, "Grade: " + pass});


            System.out.println ("Would you like to see previous results? y/n");


            //'Previous results' question loop
            do {
                ans = input.next().charAt(0);
                    if (!ans.equals('y')  ||  !ans.equals('n')) {
                        System.out.println ("Input must be either 'y' or 'n'");
                    }
            } while (!ans.equals('y')  ||  !ans.equals('n'));


            // Close or Array if statement
            if (ans.equals('y')) {
                for (Object[] row : prevResults) {
                        System.out.println("Results = " + Arrays.toString(row));
                }
            } //
            else if (ans.equals('n')) {
                System.out.println("Negative");
                //System.exit(0); 
            }
        }// end for 
    }//end main
}//end class

EDIT 2: I have switch computers and all the suggested answers to indeed work. They being

while (ans != 'y' && ans != 'n');

AND

while (!(ans.equals('y')  ||  ans.equals('n')));

AND

Making a separate method as suggested by Chris Browne.

For the benefit of anyone else who reads this, these solutions work wonderfully although I have not had time to look at the BufferedReader suggested by Greg Hewgill I will most likely implement it because it seems like a better option from what he has stated.

Aidan W.
  • 13
  • 1
  • 5
  • Your use of `Scanner` is prone to errors and unexpected results, especially with interactive programs. Must you use `Scanner`? Have you considered alternatives? For example, [`BufferedReader`](http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html) has a `readLine()` method. – Greg Hewgill Mar 09 '12 at 10:48
  • I wasn't aware of any alternatives to be honest. I was told that this method would work for reading by the tutorial lecturer so I didn't think much off an alternative. As I said, I am fairly new to programming. I will investigate BufferedReader to see if it offers a solution. – Aidan W. Mar 09 '12 at 10:58

5 Answers5

4

First, an error in your code:

System.out.println ("Loop " + (++i) + " out of 5");

You should not increment i as it is already incremented in your for update statement - you are getting the wrong iteration count as a result.

Next, your should not use equals to compare char values - use == instead. When you use equals, a lot of unnecessary things happen due to the auto-boxing, that ultimately result in roughly characterObject.equals(anotherCharacterObject), objects being of type java.lang.Character. Just use e.g. ans == 'y' instead.

Last, as folks have pointed out, you should rewrite your do-while as:

do {
    ans = input.next().charAt(0);
    if (ans != 'y' && ans != 'n') {
        System.out.println ("Input must be either 'y' or 'n'");
    }
} while (ans != 'y' && ans != 'n');

or even have a separate method for the condition check (thanks to Chris Browne).

Alexander Pavlov
  • 31,598
  • 5
  • 67
  • 93
  • Ahh this was helpful. I was originally using string as opposed to Char but I was forced to change it as I was getting an error with string reading my 'enter' as a character. I did not know that == worked with Char also because as I found out, it did not with string :P I will rewrite my do-while as suggested and see if it produces a result. – Aidan W. Mar 09 '12 at 11:05
2

The condition should be:

while (!(ans.equals('y')  ||  ans.equals('n')));

because the condition you first wrote:

while (!ans.equals('y')  ||  !ans.equals('n'));

always equals to true (every character is not y or not n).

And say thanks to De Morgan, also see my answer here.

Community
  • 1
  • 1
MByD
  • 135,866
  • 28
  • 264
  • 277
  • I tried this solution just then but it didn't appear to change anything, it still has an infinite loop for anything other than 'y'. Maybe something else is incorrect as well? – Aidan W. Mar 09 '12 at 10:53
  • On further inspection, my compiler wasn't compiling my current work but a previous version of it somehow, switching to a different computer, this method does indeed work as intended. Thank you for answering. – Aidan W. Mar 09 '12 at 11:57
1

Your condition needs to be

if (!ans.equals('y')  &&  !ans.equals('n'))

instead of

if (!ans.equals('y')  ||  !ans.equals('n'))
Chetter Hummin
  • 6,687
  • 8
  • 32
  • 44
1
  } while (!ans.equals('y')  ||  !ans.equals('n'));

says While ans is not equal to 'y' or while ans is not equal to 'n'. This will always be true (it will always be not equal to one of them)

matt freake
  • 4,877
  • 4
  • 27
  • 56
1

Your conditional logic is reversed, you're saying:

if (!ans.equals('y') || !ans.equals('n'))

Semantically, this is a very difficult line to parse, because you're saying "if answer isn't y or answer isn't n", which is a lot of logical operators in a single statement. This is probably why your error has crept in.

Really, the quick-fix is to swap the "or" for an "and", but that won't really help you understand the problem. You should refactor it to use a different approach, such as:

if(isLegalAnswer(ans))

where isLegalAnswer is defined as:

private static boolean isLegalAnswer(char ans) {
  return (ans=='y' || ans=='n');
}

This allows you to negate the whole expression (!isLegalAnswer(ans)) using a single negation.

Conventionally, I forbid myself from using more than one negation in a single statement or expression, this helps to keep code easy to read while making little or no difference to speed of execution.

Chris Browne
  • 1,582
  • 3
  • 15
  • 33