13

I'm working with eclipse IDE (Version: 3.4.2) on a mac and I have met the following issue.

When comparing between strings using equal() or equalsIgnoreCase() methods I receive false even when the string are equal. For example, the code below consider the following condition as false, even when values[0] = "debug_mode"

if (values[0].equalsIgnoreCase("debug_mode")) 
    debug_mode = true;

which is part of the following loop:

String value = dis.readLine();
String values[] = value.trim().split("=");
if (values.length >= 2)
{
    Config.prnt_dbg_msg(values[0] + "\t" + values[1]);
    if (values[0].equalsIgnoreCase("debug_mode")) 
        debug_mode = isTrue(values[1]);
    if (values[0].equalsIgnoreCase("debug_query_parsing")) 
        debug_query_parsing = isTrue(values[1]);
    if (values[0].equalsIgnoreCase("username")) 
        Connection_Manager.alterAccessParameters(values[1], null, null);
    if (values[0].equalsIgnoreCase("password")) 
        Connection_Manager.alterAccessParameters(null, values[1], null);
if (values[0].equalsIgnoreCase("database")) 
        Connection_Manager.alterAccessParameters(null, null, values[1]);
    if (values[0].equalsIgnoreCase("allow_duplicate_entries")) 
        allow_duplicate_entries = isTrue(values[1]);
}                         

I tried to use value[0].equal("debug_mode") and got the same result. Does someone have any idea why?

Paul T.
  • 714
  • 1
  • 9
  • 20
MByD
  • 135,866
  • 28
  • 264
  • 277

12 Answers12

22

That would be very strange indeed :) Can you change the above code to this:

if ("debug_mode".equalsIgnoreCase("debug_mode")) 
    debug_mode = true;

confirm it works fine and then double check why your values[0] is not "debug_mode".

Here's what comes to my mind right now as a list of things to check:

  • Check that values[0].length() == "debug_mode".length()
  • I highly doubt, but let me put it on the table anyway - are you by any chance using Unicode?
  • Can you print each character and do .equals() between that character and the respective character of the "debug_mode" string?
  • If this is in a bigger project, can you do the same in a simple Java project and confirm it works there?

To clarify, the problem is actually using DataInputStream.readLine. From javadoc (http://download.oracle.com/javase/1.6.0/docs/api/java/io/DataInputStream.html):

readLine()
      Deprecated. This method does not properly convert bytes to characters. ...

It actually has to do with Unicode in a subtle way - when you do writeChar you actually write two bytes 0 and 97, big-endian Unicode for the letter a.

Here's a self-contained snippet that shows the behavior:

import java.io.*;
import java.util.*;

public class B {
  public static void main(String[] args) throws Exception {
    String os = "abc";

    System.out.println("---- unicode, big-endian");
    for(byte b: os.getBytes("UTF-16BE")) {
      System.out.println(b);
    }

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);

    for(char c: os.toCharArray()) {
      dos.writeChar(c);
    }

    byte[] ba = baos.toByteArray();

    System.out.println("---- ba");
    for(byte b: ba) {
      System.out.println(b);
    }

    ByteArrayInputStream bais = new ByteArrayInputStream(ba);
    DataInputStream dis = new DataInputStream(bais);

    System.out.println("---- dis");
    String s = dis.readLine();
    System.out.println(s);
    System.out.println("String length is " + s.length() 
      + ", but you would expect " + os.length() 
      + ", as that is what you see printed...");
  }
}

Moral of the story - don't use deprecated api... Also, whitespace is the silent killer: http://www.codinghorror.com/blog/2009/11/whitespace-the-silent-killer.html

icyrock.com
  • 27,952
  • 4
  • 66
  • 85
  • 1
    Well, you highly doubt it, but actually the problem was that I wrote to file using DataOutputStream.writeChar() instead of writeUTF(). and it did cause the problem. – MByD Nov 18 '10 at 01:26
  • Nothing to do with it. If writeUTF() worked and writeChar() didn't, he must have been *reading* with readUTF(), which certainly wouldn't work with data not written by writeUTF(). Unicode has nothing to do with this. – user207421 Nov 18 '10 at 08:16
  • @EJP It's a mix of Unicode and deprecated API (the latter being more important) - see the edit. – icyrock.com Nov 18 '10 at 15:31
  • So it had nothing to do with writeUTF() and nothing to do with deprecation either. It had to do with reading and writing using asymmetric methods. If you wrote with writeChars() you need to read with readChar(). If you wrote with writeUTF() you needed to read with readUTF(). If you wrote with PrintStream.println() you needed to read with readLine() (deprecated or not). – user207421 Nov 19 '10 at 02:12
  • Not really - if you wrote by calling `writeChar` 5 times with last one being writing a new line character, you would expect that you could read all 5 characters into a string by calling `readLine` once. I would say it's a combination of all these factors and ambiguity of `readLine` (with respect to `writeUTF`). That's why `readLine` was deprecated. Definitively agree that you should try to be symmetric as much as you can. – icyrock.com Nov 19 '10 at 03:57
  • No, you wouldn't expect that if you had read the Javadoc, where it clearly says it converst successive bytes to characters. Not byte pairs. – user207421 Nov 19 '10 at 05:09
  • I don't say this deprecated implementation works as I would expect (clearly, it does not) - I said I would expect that if I used the method called `writeChar` and write `abcd\n` to a stream, I would expect the method called `readLine` to return a string `"abcd"`. It's not a good thing if you need to read javadoc to confirm that `readLine` does not read lines, which I would assume is a list of characters terminated by a new line, just because it doesn't consider characters the same way `writeChar` does. Fair enough remarks from your side - definitively, you are right on the implementation. – icyrock.com Nov 19 '10 at 05:33
  • [new InputStreamReader(i, "utf8")] solved my problem too, thanks. – Vahid Jan 17 '17 at 10:32
7

I have just had this exact same issue, using equalsIgnoreCase.

After hours of staring at the screen, debugging the code it dawned on me that my if statement had a ; at the end,

i.e.

if ("stupid".equalsIgnoreCase.("STupid");
{
     //it always gets here 

}

Hope this helps someone in future.

Jason
  • 71
  • 1
  • 2
  • I thought you were a stupid because of that stupid error, but... I thought to myselft: "It's always human errors, so, let me check my code". And what happend? It was your same error!! :P And I have almost an hour with this – Sterling Diaz Oct 18 '14 at 01:24
  • Similarly, I had a problem with trying to return from a method using this type of check. ```if ("stupid".equalsIgnoreCase.("STupid")) return;``` I had to wrap the return block: ```if ("stupid".equalsIgnoreCase.("STupid")) { return; }``` – providencemac Mar 31 '16 at 21:01
  • You can also avoid this potential problem by putting the opening { on the same line as the IF Statement. That's what I do. That way if you add an unintended ";" anywhere you will almost certainly cause a compile problem due to bracket mismatch. – Warren K May 13 '20 at 11:28
3

I'm with the others, this is crazy and shouldn't happen. I agree that printing it out may help, but I'm going to assume you've tried that.

Is it possible it's a localization issue? That is, when you type in debug_mode in the editor (for the string) it's the string "debug_mode", but when you type the string in during execution the terminal is set to use a different language and you're getting a different (but identical looking) character?

To find out, loop through the string you get in and print out each character's integer value, and then do the same with your string that's hardcoded and see if they are the same.

String value = dis.readLine();
String values[] = value.trim().split("=");

System.out.println("Input:");

for (int i = 0; i < values[0].length(); i++) {
    System.out.print((int) values[0].charAt(i));
    System.out.print(' ');
}

System.out.println("Hardcoded:");

String debugMode = "debug_mode";

for (int i = 0; i < debugMode.length(); i++) {
    System.out.print((int) debugMode.charAt(i));
    System.out.print(' ');
}

Now for this to work, you'd have to type the code (or at least the debug_mode constant) so it has the same character set as you are using.

I'd be willing to bet a good sum of money this isn't the issue, but even if it isn't it should prove instructive and show you what is different.

MBCook
  • 14,424
  • 7
  • 37
  • 41
2

Try compareToIgnoreCase:

if (values[0].compareToIgnoreCase("debug_mode") != 0) 
    debug_mode = true;

And if that doesn't work, try compareTo instead.

And if that doesn't work, try:

String d = (String)values[0];
if (d.compareToIgnoreCase("debug_mode") != 0) 
        debug_mode = true;

And if those don't work, you have a serious Java issue. Either it's ancient or it doesn't like you.

Evan Mulawski
  • 54,662
  • 15
  • 117
  • 144
  • There is no version of Java ancient or modern where these methods do not work correctly. It wouldn't have been able to compile itself for a start. – user207421 Nov 18 '10 at 08:15
2

Although there are few very good and correct answers above I would still like to mention my personal experience so that anyone facing same problem could get instant help from this answer.

I had two different string say string A and string B coming from diffrent sources, they seemed identical to me but I was getting not equal for them on using equals method

even on using equalsIgnoreCase gave me false

I was clueless because when I was printing those string (A & B) to check what they look like they were

String A is dsycuii343qzx899+ty=
String B is dsycuii343qzx899+ty=

so, I then checked length of the two string which gave me the clue

String A length = 20
String B length = 21

SO that means I might be missing something,

so what I did was

I checked each String char by char and I got to know the problem

String A which seemed like dsycuii343qzx899+ty= was actually dsycuii343qzx899+ty=\n

i.e there was a LF (new line character) at the end which was noticed while Log check

hope it might help someone.

eRaisedToX
  • 3,221
  • 2
  • 22
  • 28
0

You can easily run into this on Android with SpannableString, like when a TextView has autolinking enabled, for instance:

// Outputs "a string"
Log.d("test", "TextView text: " + textView.getText());

// Outputs "a string"
Log.d("test", "Text to match: " + "a string");

if( textView.getText().equals("a string") )
{
    // Won't get here
}

You can do a quick test to see what kind of string textView.getText() returns by doing:

Log.d("test", "String class: " + textView.getText().getClass().getSimpleName());

If indeed you've got a SpannableString, you simply need to call toString() on it for the if condition to be satisfied:

if( textView.getText().toString().equals("a string") )
{
    // We're here
}
dvs
  • 12,324
  • 6
  • 38
  • 45
0

On a different note, I had a JSP page having similar problems while comparing the retrieved "status" of a table:

try{



  // ID is a Primary Key (unique). STATUS column data type in DB: CHAR(20)
  rs = stmt.executeQuery("select STATUS from TEMP_TABLE WHERE ID='"+id+"'");

  while(rs.next()){

        status = (String) rs.getString("STATUS");

  }
   if ( status.equalsIgnoreCase("active") )
   {
          // Run some DB Queries
   } else {
           out.write("Page can't be accessed due to status : " + status);
   }
} catch(Exception e) { e.getMessage(); }
finally {
         //close all open objects
}

For reasons unknown to me it always hits the else block with message "Page can't be accessed due to status : active", though status is "active". I tried closing rs and stmt objects after each query before and after running this Query but that didn't helped. Eventually I changed my Query to

"select STATUS from TEMP_TABLE WHERE ID='"+id+"' where STATUS='ACTIVE'"
Suresh
  • 1,687
  • 1
  • 10
  • 4
0

I think the problem may be that although the actual String values are equal, their underlying byte[]'s may not be.

Try using this method to compare the two byte[]'s:

private String printBytes(String str) {
    byte[] bytes = str.getBytes(ENCODING);
    String output = "byte[";
    for (int i = 0; i < bytes.length; i++) {
        output += Byte.toString(bytes[i]);
        if (i < bytes.length - 1) {
            output += ", ";
        }
    }
    output += "]";
    return output;
}

For example:

Charset ENCODING = Charset.forName("UTF-8");
Log.d(LOG_TAG, "string1: \"" + string1 + "\" - " + printBytes(string1));
Log.d(LOG_TAG, "string2: \"" + string2 + "\" - " + printBytes(string2));

This would enable a visual comparison. For long Strings, you could compare the byte[]'s programmatically by iterating through both arrays at the same time and comparing the values.

ban-geoengineering
  • 18,324
  • 27
  • 171
  • 253
0

In my case I just discovered one string had space before the string. My strings were like " SUCCESS" and "SUCCESS", so it was returning false. I used:

 String st1=st.replaceAll("\\s","");

and thus problem solved.

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
Debasish Ghosh
  • 1,867
  • 20
  • 29
0

May be my answer is very later but it will be useful to someone.

Just trim() both the strings before comparison

       eg: if(data1.trim().equalsIgnoreCase(data2.trim()))
            {
                //This gives proper result
            }
0

Can be byte order mark: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8

just try str1.length() and str2.length() and if it is not the same do str1.charAt(0) and y=if you get something like '\uFEFF' 65279 than that is your issue

dfostic
  • 1,608
  • 15
  • 8
0

You should use the InvariantCulture parameter

String.Equals(string1, string2, StringComparison.InvariantCultureIgnoreCase))