mgus
mgus

Reputation: 808

How does object.equals method is supposed to work in Java?

This is my source code. I'trying to implement a simple program that asks a question to a user and expects the answer to be "yes" or "no" and terminates only if the user answer to the question "yes" or "no". The book I have suggested me not to use == comparison and to use the equals method instead, so that the program can understand if the user typed "y e s" instead of "yes". But in this way the result is the same and the method seems to compare the user's answer if it is exactly "yes" or "no". It doesn't accept for example an aswer of "n o". Is that logical for that method? Is it supposed to work that way? How can I change the program to accept answers like "Yes" "ye s" "No" "NO" etc.? I would appreciate your help:)

import acm.program.*;

public class YesNoExample extends ConsoleProgram{
public void run(){
    while(true){
    String answer = readLine("Would you like instructions? ");
    if(askYesNoQuestion(answer)){
        break;
    }
    println("Please answer yes or no.");
    }
}

private boolean askYesNoQuestion(String str){
    if(str.equals("yes")||str.equals("no")){
        return true;
    }else{
        return false;
    }
}

}

Upvotes: 0

Views: 733

Answers (4)

Marko Topolnik
Marko Topolnik

Reputation: 200148

If you need to fuzzily identify yes/no, first you need exact rules as to what matches. Based on your examples, I can suggest this:

private boolean askYesNoQuestion(String str) {
  str = str.replace(" ", "").toUpperCase();
  return str.equals("YES") || str.equals("NO");
}

If interested in top performance and not at all in intelligibility, use this:

private static final Pattern p = 
    Pattern.compile("y\\s*e\\s*s|n\\s*o", Pattern.CASE_INSENSITIVE);
private boolean askYesNoQuestion(String str) {
  return p != null && p.matcher(str.trim()).matches();
}

Upvotes: 1

user177800
user177800

Reputation:

Semantics of == vs .equals()

First off you misunderstand the semantics.

== tests for object identity. A == B says is A a reference to the exact same object as B.

.equals() applies custom logic to test if the objects are equal in some logical manner, without being the exact same object. For this to be implemented correct, both objects should have the same .hashCode() value as well.

Idiomatic Java Solution

Since the String object is final which means it can't be inherited from. You can't override the .equals() on the String object.

What you need to do is preprocess the input into something that can be directly compared to the target value with .equalsIgnoreCase().

One way to do this is use, answer.replaceAll("\\s","") to remove all the whitespace then you can compare it to your target String literal with .equalsIgnoreCase().

A better method to replace askYesNoQuestion() would be:

private boolean isAnswerYesOrNo(final String answer)
{
    final String input = answer.replaceAll("\\s","");
    return "yes".equalsIgnoreCase(input) || "no".equalsIgnoreCase(input);
}

Comparing a literal to the input parameter will insulate you from NullPointerExceptions if the input parameter happens to be null "yes".equalsIgnoreCase()can never throw aNullPointerException`. This is idiomatic Java.

Get a better book

That book isn't very useful if it really says what you are claiming it says. Also it is teaching you to write lots of code to handle bad input when that is a complete anti-pattern and a well designed program would exit with a verbose explanation of the exact problem was what can be done to fix the input.

Upvotes: 0

Matt
Matt

Reputation: 11805

With the explanation of == and .equals well described above, here's a two examples of a one liner that does the comparison you want.

if ( Pattern.matches("\\s*[yY]\\s*[eE]\\s*[sS]\\s*", input) ) {
  // do something
}


if ( input.replaceAll("\\s", "").equalsIgnoreCase("yes") ) {
  // do something
}

Upvotes: -1

Miquel
Miquel

Reputation: 15675

If you use == you'll be comparing the references (memory pointers) of two String objects. If you use equals, a custom made method in the String class will be run that does some "intelligent" comparison, in this case, check that the characters are all the same, and the whole thing has the same length.

If you'd like to support mixed case letters, you could use "someString".equalsIgnoreCase("SoMeString") (which will return true). This is done (said roughly) by making both strings lowercase (so the case doesn't matter) and comparing them using equals.

Edit: The other posters made me realize that, in addition to capitalization, you also want to look for String equality where spaces don't matter. If that's the case, a similar trick to turning everything to lowercase applies, where you first remove all the spaces, as @LouisWasserman says in his answer

Upvotes: 2

Related Questions