How does object.equals method is supposed to work in Java? - 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;
}
}
}

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

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();
}

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.

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
}

Related

Can't get else if statement to work in Java

Ok I am trying to make this simple thing but it won't work. I am a beginner in Java and would like some help. Every time I run the code below I get the output That is not a valid option. What am I doing wrong?
package test;
import java.util.Scanner;
public class options {
public void options() {
Scanner scnr = new Scanner(System.in);
String slctn;
System.out.println("What would you like to do?");
System.out.println("a) Travel the expedition");
System.out.println("b) Learn more about the expedition");
slctn = scnr.nextLine();
if (slctn == "a"){
travel exeTravel = new travel();
exeTravel.travel();
}else if (slctn=="b"){
learn exeLearn = new learn();
exeLearn.learn();
}else{
System.out.println("That is not a valid option");
}
}
}
Well, first off, == is a fundamental operator in the language. The result type of the expression is a boolean. For comparing boolean types, it compares the operands for the same truth value. For comparing reference types, it compares the operands for the same reference value (i.e., refer to the same object or are both null). For numeric types, it compares the operands for the same integer value or equivalent floating point values. See the Java Language Specification.
In contrast, equals() is an instance method which is fundamentally defined by the java.lang.Object class. This method, by convention, indicates whether the receiver object is "equal to" the passed in object. The base implementation of this method in the Object class checks for reference equality. Other classes, including those you write, may override this method to perform more specialized equivalence testing. See the Java Language Specification.
The typical "gotcha" for most people is in using == to compare two strings when they really should be using the String class's equals() method. From above, you know that the operator will only return "true" when both of the references refer to the same actual object. But, with strings, most uses want to know whether or not the value of the two strings are the same -- since two different String objects may both have the same (or different) values.
slctn = scnr.nextLine();
if (slctn.equals("a")){
travel exeTravel = new travel();
exeTravel.travel();
}else if (slctn.equals("b")){
learn exeLearn = new learn();
exeLearn.learn();
}else{
System.out.println("That is not a valid option");
}
slctn.equals("a") will work.
Read this to understand why: What is difference between == and equals() in java?
In Java, when you need to compare two objects for equality (that is, to determine if they have the same value) you must use equals(). The == operator is used for testing if two objects are identical, that is: if they're exactly the same object in memory. In your code, replace this:
slctn == "a"
slctn == "b"
With this:
"a".equals(slctn)
"b".equals(slctn)
Also notice that it's a good idea to invert the order of the comparison ("a" before slctn), just in case slctn is null.
In java when matching any object the == operator will only match the reference of those two objects.
If we take your example slctn == "a". Say slctn has its reference value at abc123, your other sting "a" will have a different reference value as it is not the same object.
The method .equals checks what the letters in the string object are and matches the value of the letters in the two strings. Therefore if your object slctn contains "a", it will match with the string "a"
In java == operator compare reference of two objects, for sample :
String s_1 = new String("Sample");
String s_2 = new String("Sample");
System.out.println(s_1 == s_2);
result will is :
false
this happen because s_1 is a reference at memory and s_2 is difference refernce at memroy also.
For solve this issue , you have to compare tow objects by equals method. for sample
String s_1 = new String("Sample");
String s_2 = new String("Sample");
System.out.println(s_1.equals(s_2));
result will is :
true

java comparing two Pattern objects

Is there an easy way to compare two Pattern objects?
I have a Pattern which compiled using the regex "//" to check for comments in a code.
Since there are several regex to describe comments, I want to find a way to difference them.
How can it be done? the Pattern class does not implements the equals method.
You can compare Pattern objects by comparing the result of calling pattern() or toString but this doesn't do what you want (if I understand your question correctly). Specifically, this compares the strings that were passed to the Pattern.compile(...) factory method. However, this takes no account of flags passed separately to the pattern string.
There is no simple way to test if two non-identical regexes are equivalent. For example ".+" and "..*" represent equivalent regexes, but there is no straight-forward way to determine this using the Pattern API.
I don't know if the problem is theoretically solvable ... in the general case. #Akim comments:
There is no finite axiomatization to regex equivalence, so the short answer is "this is not doable by tree transformations of the regexes themselves". However one can compare the languages of two automata (test their equality), so one can compute whether two regexes are equivalent. Note that I'm referring to the "genuine" regexes, with no extensions such as back-references to capture groups, which escape the realm of rational languages, i.e., that of automata.
I also want to comment on the accepted answer. The author provides some code that he claims shows that Pattern's equals method is inherited from Object. In fact, the output he is seeing is consistent with that ... but it doesn't show it.
The correct way to know if this is the case is to look at the javadoc ... where the equals method is listed in the list of inherited methods. That is definitive.
So why doesn't the example show what the author says it shows?
It is possible for two methods to behave the same way, but be implemented differently. If we treat the Pattern class as a black box, then we cannot show that this is not happening. (Or at least ... not without using reflection.)
The author has only run this on one platform. Other platforms could behave differently.
On the second point, my recollection is that in the earlier implementation of Pattern (in Java 1.4) the Pattern.compile(...) methods kept a cache of recently compiled pattern objects1. If you compiled a particular pattern string twice, the second time you might get the same object as was returned the first time. That would cause the test code to output:
true
true
true
true
But what does that show? Does it show that Pattern overrides Object.equals? No!
The lesson here is that you should figure out how a Java library method behaves primarily by looking at the javadocs:
If you write a "black box" test, you are liable to draw incorrect conclusions ... or at least, conclusions that may not be true for all platforms.
If you base your conclusions on "reading the code", you run the risk of drawing conclusions that are invalid for other platforms.
1 - Even if my recollection is incorrect, such an implementation would be consistent with the javadocs for the Pattern.compile(...) methods. They do not say that each compile call returns a new Pattern object.
Maybe I do not fully understand to the question. But as you can see in the following example, there is a default java.lang.Object.equals(Object) method for every Java Object. This method compares the references to the objects, i.e. uses the == operator.
package test;
import java.util.regex.Pattern;
public class Main {
private static final Pattern P1 = Pattern.compile("//.*");
private static final Pattern P2 = Pattern.compile("//.*");
public static void main(String[] args) {
System.out.println(P1.equals(P1));
System.out.println(P1.equals(P2));
System.out.println(P1.pattern().equals(P1.pattern()));
System.out.println(P1.pattern().equals(P2.pattern()));
}
}
Outputs:
true
false
true
true
For mysterious reasons, the Pattern object doesn't implement equals(). For example, this simple unittest will fail:
#Test
public void testPatternEquals() {
Pattern p1 = Pattern.compile("test");
Pattern p2 = Pattern.compile("test");
assertEquals(p1, p2); // fails!
}
The most common workaround for this seems to be to compare the string representations of the Pattern objects (which returns the String used to create the Pattern):
#Test
public void testPatternEquals() {
Pattern p1 = Pattern.compile("test");
Pattern p2 = Pattern.compile("test");
assertEquals(p1.toString(), p2.toString()); // succeeds!
}
Pattern doesn't but String does. Why not just compare the regex from which the Patterns were compiled?
I know automata may solve your problem. But that maybe complicated.
Roughly, you should compare pattern.pattern() and pattern.flags() at-least, though it‘s not enough to decide whether two regex are equivalent or not.
You can compare string representations from which patterns have been made:
Pattern p1 = getPattern1();
Pattern p2 = getPattern2();
if (p1.pattern().equals(p2.pattern())){
// your code here
}
I think I get the idea of the question and since I searched for ways to compare Patterns I end up here (two years too late probably, well, sorry...).
I'm writing tests and I need to know if a method of mine returns the expected pattern. While the text via toString() or pattern() might be the same, the flags can be different and the result when using the pattern would be unexpected.
A while ago I wrote my own general implementation of toString(). It collects all fields including the private ones and constructs a string that can be used for logging and apparently for testing. It showed that fields root and matchRoot were different when compiling two equal patterns. Assuming that those two aren't that relevant for equality and since there is a field flag, my solution is quite good if not perfect.
/**
* Don't call this method from a <code>toString()</code> method with
* <code>useExistingToString</code> set to <code>true</code>!!!
*/
public static String toString(Object object, boolean useExistingToString, String... ignoreFieldNames) {
if (object == null) {
return null;
}
Class<? extends Object> clazz = object.getClass();
if (useExistingToString) {
try {
// avoid the default implementation Object.toString()
Method methodToString = clazz.getMethod("toString");
if (!methodToString.getDeclaringClass().isAssignableFrom(Object.class)) {
return object.toString();
}
} catch (Exception e) {
}
}
List<String> ignoreFieldNameList = Arrays.asList(ignoreFieldNames);
Map<String, Object> fields = new HashMap<String, Object>();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
String fieldName = field.getName();
if (ignoreFieldNameList.contains(fieldName) || fields.containsKey(fieldName)) {
continue;
}
boolean accessible = field.isAccessible();
if (!accessible) {
field.setAccessible(true);
}
try {
Object fieldValue = field.get(object);
if (fieldValue instanceof String) {
fieldValue = stringifyValue(fieldValue);
}
fields.put(fieldName, fieldValue);
} catch (Exception e) {
fields.put(fieldName, "-inaccessible- " + e.getMessage());
}
if (!accessible) {
field.setAccessible(false);
}
}
// travel upwards in the class hierarchy
clazz = clazz.getSuperclass();
}
return object.getClass().getName() + ": " + fields;
}
public static String stringifyValue(Object value) {
if (value == null) {
return "null";
}
return "'" + value.toString() + "'";
}
And the test is green:
String toString1 = Utility.toString(Pattern.compile("test", Pattern.CASE_INSENSITIVE), false, "root", "matchRoot");
String toString2 = Utility.toString(Pattern.compile("test", Pattern.CASE_INSENSITIVE), false, "root", "matchRoot");
assertEquals(toString1, toString2);
To determine whether two Pattern objects are equivalent, the simplest thing to do is to compare the actual string pattern and the flags used to create that pattern:
boolean isPatternEqualToPattern(final Pattern p1, final Pattern p2) {
return p1.flags() == p2.flags() &&
p1.pattern().equals(p2.pattern());
}
Although the other answers might solve the problem, I do not think they are the real answer to the problem.
If you really want to compare two patterns you essentially want to compare two regular languages.
To do this, cs stackexchange has already posted a solution:
https://cs.stackexchange.com/questions/12876/equivalence-of-regular-expressions
A fast method to check the equivalence of regular languages is the Hopcroft and Karp algorithm (HK).
Here is a java implementation of the algorithm:
http://algs4.cs.princeton.edu/65reductions/HopcroftKarp.java.html

Comparing two identical strings with == returns false [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am making an archive for my family. There are no syntax errors, however whenever I type in "Maaz", it evaluates realName == "Maaz" to false and goes to the else statement.
import java.util.Scanner;
public class MainFamily {
public static void main (String [] args) {
System.out.println("Enter you're name here");
Scanner name = new Scanner(System.in);//Scanner variable = name
String realName;
realName = name.nextLine();//String variable = user input
System.out.println("Name: "+ realName);
if (realName == "Maaz") {
System.out.println("Name: Maaz");
} else {
System.out.println("This person is not in the database");
}
}
}
TL;DR
You wrote (this doesn't work):
realName == "Maaz"
You meant this:
realname.equals("Maaz")
or this:
realname.equalsIgnoreCase("Maaz")
Explanation
In Java (and many other Object-Oriented programming languages), an object is not the same as a data-type. Data-types are recognized by the runtime as a data-type.
Examples of data-types include: int, float, short.
There are no methods or properties associated with a data-type. For example, this would throw an error, because data-types aren't objects:
int x = 5;
int y = 5;
if (x.equals(y)) {
System.out.println("Equal");
}
A reference is basically a chunk of memory that explicitly tells the runtime environment what that data-block is. The runtime doesn't know how to interpret this; it assumes that the programmer does.
For example, if we used Integer instead of int in the previous example, this would work:
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x.equals(y)) {
System.out.println("Equal");
}
Whereas this would not give the expected result (the if condition would evaluate to false):
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x == y) {
System.out.println("Equal");
}
This is because the two Integer objects have the same value, but they are not the same object. The double equals basically checks to see if the two Objects are the same reference (which has its uses).
In your code, you are comparing an Object with a String literal (also an object), which is not the same as comparing the values of both.
Let's look at another example:
String s = "Some string";
if (s == "Some string") {
System.out.println("Equal");
}
In this instance, the if block will probably evaluate to true. Why is this?
The compiler is optimized to use as little extra memory as is reasonable, although what that means depends on the implementation (and possibly runtime environment).
The String literal, "Some string", in the first line will probably be recognized as equivalent to the String literal in the second line, and will use the same place in memory for each. In simple terms, it will create a String object and plug it into both instances of "Some string". This cannot be relied upon, so using String.equals is always a better method of checking equivalence if you're only concerned with the values.
do this instead
if (realName.equals("Maaz"))
equals() should be used on all non-primitive objects, such as String in this case
'==' should only be used when doing primitive comparisons, such as int and long
use
if(realName.equals("Maaz"))
use == with primitive data type like int boolean .... etc
but if you want to compare object in java you should use the equals method
You have to compare objects with realName.equals ("Maaze"), not with ==.
It is best practice to compare Strings using str.equals(str2) and not str == str2. As you observed, the second form doesn't work a lot of the time. By contrast, the first form always works.
The only cases where the == approach will always work are when the strings are being compared are:
string literals or references to string literals, or
strings that have been "interned" by application-level code calling str = str.intern();.
(And no, strings are not interned by default.)
Since it is generally tricky to write programs that guarantee these preconditions for all strings, it is best practice to use equals unless there is a performance-related imperative to intern your strings and use ==.
Before that you decide that interning is a good idea, you need to compare the benefits of interning with the costs. Those costs include the cost of looking up the string in the string pool's hash table and the space and GC overheads of maintaining the string pool. These are non-trivial compared with the typical costs of just using a regular string and comparing using equals.
You can also use
realname.equalsIgnoreCase("Maaz")
This way you can accept Maaz, maaz, maaZ, mAaZ, etc.
== tests shallow equality. It checks if two objects reference the same location in memory.
Intriguing. Although, as others have stated, the correct way is to use the .equals(...) method, I always thought strings were pooled (irrespective of their creation). It seems this is only true of string literals.
final String str1 = new String("Maaz");
final String str2 = new String("Maaz");
System.out.println(str1 == str2); // Prints false
final String str3 = "Laaz";
final String str4 = "Laaz";
System.out.println(str3 == str4); // Prints true
Since you are working on strings, you should use equals to equalsIngnorecase method of String class. "==" will only compare if the both objects points to same memory location, in your case, both object are different and will not be equal as they dont point to same location. On the other hand, equals method of String class perform a comparison on the basis of the value which objects contains. Hence, if you will use equals method, your if condition will be satisfied.
== compares object references or primitive types (int, char, float ...)
equals(), you can override this method to compare how both objects are equal.
for String class, its method equal() will compare the content inside if they are the same or not.
If your examples, both strings do not have the same object references, so they return false, == are not comparing the characters on both Strings.
It seems nobody yet pointed out that the best practice for comparing an object with a constant in Java is calling the equals method of the constant, not the variable object:
if ("Maaz".equals (realName)) {}
This way you don't need to additionally check if the variable realName is null.
if(realName.compareTo("Maaz") == 0) {
// I dont think theres a better way do to do this.
}

Why do != and == not behave like the equals method in Java? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Java String.equals versus ==
whats the difference between ".equals and =="
public String getName() {
return new String("foobar");
}
if(getName() != "foobar2") {
//Never gets executed, it should, wtf!.
}
if(!getName().equals("foobar2")) {
//This works how it should.
}
So yeah my question is simple.. why doesn't != behave the same as !equals() aka (not Equals).
I don't see any logicial reason why one should fail, both are the same exact code in my mind, WTH.
Looking at java operators
http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
You can clearly see
equality == !=
are the equality operators, sure I usually use != only on numbers.. but my mind started wandering and why doesn't it work for String?
EDIT:
Here's something that looks more like the actual issue..
for (ClassGen cg : client.getClasses().values()) {
final ConstantPoolGen cp = cg.getConstantPool();
if(cp.lookupInteger(0x11223344) != -1) {
for (Method m : cg.getMethods()) {
System.out.println("lots of class spam");
if(m.getName() != "<init>") continue;
System.out.println("NEVER GETS HERE, 100% SURE IT HAS CONSTRUCTOR LOL");
}
}
}
Using != means that you check for the instance reference in the memory, and the same instance will give you true on that comparison.
When you do a new String("foobar"), a new "foobar" is created in the memory, and the comparison using == returns false.
Calling a intern() on that new string may change this behavior, since the String will now be grabbed or added to the String pool.
In any case, it's safer to use the 'equals()'.
public static void main(String[] args) throws Exception {
if (getName() != "foobar2") {
System.out.println("1");
}
if (!getName().equals("foobar2")) {
System.out.println("2");
}
}
public static String getName() {
return new String("foobar");
}
For me this outputs:
1
2
But those two checks are not equivalent. The first check is checking whether the object returned by getName() is the same object that was created for the string literal "foobar2", which it's not. The second check is probably the one you want, and it checks that the VALUE of the String object returned by the getName() method is equal to the VALUE of the String object created for your "foobar2" string literal.
So both checks will return true, the first one because they aren't the same object and the second one because the values aren't the same.
A string is an Object, not a primitive.
== and != compare two primitives to each other.
To compare strings you need to loop trough each character and compare them in order which is what .equals() does.
If you do any OOP in Java you need to override equals when you want to do equality checks on the Objects, and implement Comparable and .compare() if you want to be able to do things like sort them.
Here is a quick example of equals:
public class Person {
public name;
public Person(String name) {
this.name = name;
}
public boolean equals(Object o){
if(o instanceof Person)
if(this.name.equals(o.name))
return true;
return false;
}
}
Now a Person can be compared to another Person like:
person1.equals(person2)
Which will only return true if both people have the same name. You can define what makes two objects equal however you want, but objects are only == if they are really just two pointers to the same object in memory.
Operators only apply to primitives, not Objects, so a String comparison must be done equals, as that operates at the Object level.
--EDIT--
My comment was meant more along the lines of "the value of an Object cannot be compared in the expected way as in other languages". Of course you can use == signs, but not for a textual comparison. This is the classic question that is asked every time someone migrates to Java from a scripting language, or another language that does support operators for text comparison on Strings.

Is there a shorthand way to write the Javascript code 'a||"text"' in Java?

When I need to display a value that might be null/undefined in Javascript, I usually just write:
console.log(a||"");
Or something similar. Is there a similar way to do this in Java other than:
System.out.println(a!=null?a:"");
I think that your System.out.println(a!=null?a:""); is a very clear way to output what you are looking for.
It uses the ternary operator and seems to make sense.
(condition) ? (if true) : (if false);
The best you can do besides using the ternary operator is to create a very short method to do the same. Perhaps "ns" for "nullable string":
public static String ns(String nullableString) {
return nullableString == null ? "" : nullableString;
}
Then you can write "System.out.println(ns(a));" However, the ternary operator is clearer - I would only do something like the above if I were doing this all over the place.
You have ternaries:
a != null ? a : ""
There isn't, as the others answers suggest. That is because in JS, boolean operators don't necessarily return booleans, they return the value of the object that caused the expression to short-circuit. However, in Java, as in C and other languages, boolean operators always return boolean, so you don't have that convenient way of defaulting a value a = b || c or to prevent a null pointer a = b && b.getValue()
You can do a function that doesn't print null when its null.
I don't know java but a prototype will be
function safePrint(object a)
{
System.out.println(a!=null?a:"");
}
and then just write
safePrint(a);
Although if you are looking for short code use an interpreted language like javascript or perl. compiled languages like java is just not meant for fast and short coding.
If the variable is not initialized, java will not compile. Undefined is unacceptable in Java.
If you have a variable named "blueberry" and you want to display the value on the console, you can do this:
System.out.println(blueberry);
This code will display "null" on the console if blueberry is null.
Here is a simple demonstration
public class Outty
{
public static void main(String[] args)
{
String blueberry = null;
System.out.println(blueberry);
blueberry = "7";
System.out.println(blueberry);
}
}

Categories