ColdFusion String Comparison: Compare() vs. Equals() vs. CompareTo()

Posted September 5, 2006 at 1:12 PM

Tags: ColdFusion

As part of my on-going study of the Java that lives under ColdFusion, I thought I would test out some string comparison methods so see if going directly to the Java methods would be any faster than using the ColdFusion methods. For this, I compared the following:

  1. Compare() - Built into ColdFusion
  2. String::CompareTo() - Built into Java string
  3. String::Equals() - Built into Java string
  4. String::EqualsIgnoreCase() - Built into Java string

Compare( strOne, strTwo )

Compare takes two strings and does what I assume is some sort of Bit manipulation to figure out if two strings are equal. If the two strings are equal, it returns zero. If the first string is "less than" the second string, it returns -1. If the first string is "greater than" the first, it returns 1.

String::CompareTo( strOne | objOne )

The Java string method CompareTo takes either a string or an object and tests for equality. I am not 100% sure, but I believe the return values to be that of the ColdFusion Compare method.

String::Equals( objOne )

The Java string method Equals takes an object and compares it to the string. This returns a boolean true/false.

String::EqualsIgnoreCase( strOne )

The Java string method EqualsIgnoreCase takes a string object and compares it to the string ignoring case. This returns a boolean true/false.

Now, for the test:

 Launch code in new window » Download code as text file »

  • <!---
  • Start off with a test statement. This is the string to
  • which we will be comparing dynamic strings.
  • --->
  • <cfset strStatement = "I like girls that weigh 165 lbs." />
  •  
  • <!--- Set the number of iterations for testing. --->
  • <cfset intIterations = 5000 />
  •  
  •  
  • <!--- Test the ColdFusion Compare() method. --->
  • <cftimer label="NOT Compare" type="outline">
  •  
  • <!--- Loop for speed testing. --->
  • <cfloop index="intI" from="1" to="#intIterations#" step="1">
  •  
  • <!--- Create random test string. --->
  • <cfset strTest = (
  • "I like girls that weigh " &
  • NumberFormat( intI, "000" ) &
  • " lbs."
  • ) />
  •  
  • <!--- Check to see if the statements match up. --->
  • #YesNoFormat(
  • NOT Compare( strStatement, strTest )
  • )#
  •  
  • </cfloop>
  •  
  • </cftimer>
  •  
  •  
  • <!--- Test the Java String::CompareTo() method. --->
  • <cftimer label="CompareTo" type="outline">
  •  
  • <!--- Loop for speed testing. --->
  • <cfloop index="intI" from="1" to="#intIterations#" step="1">
  •  
  • <!--- Create random test string. --->
  • <cfset strTest = (
  • "I like girls that weigh " &
  • NumberFormat( intI, "000" ) &
  • " lbs."
  • ) />
  •  
  • <!--- Check to see if the statements match up. --->
  • #YesNoFormat(
  • strStatement.CompareTo( strTest )
  • )#
  •  
  • </cfloop>
  •  
  • </cftimer>
  •  
  •  
  • <!--- Test the Java String::Equals() method. --->
  • <cftimer label="Equals" type="outline">
  •  
  • <!--- Loop for speed testing. --->
  • <cfloop index="intI" from="1" to="#intIterations#" step="1">
  •  
  • <!--- Create random test string. --->
  • <cfset strTest = (
  • "I like girls that weigh " &
  • NumberFormat( intI, "000" ) &
  • " lbs."
  • ) />
  •  
  • <!--- Check to see if the statements match up. --->
  • #YesNoFormat(
  • strStatement.Equals( strTest )
  • )#
  •  
  • </cfloop>
  •  
  • </cftimer>
  •  
  •  
  • <!--- Test the Java String::EqualsIgnoreCase() method. --->
  • <cftimer label="EqualsIgnoreCase" type="outline">
  •  
  • <!--- Loop for speed testing. --->
  • <cfloop index="intI" from="1" to="#intIterations#" step="1">
  •  
  • <!--- Create random test string. --->
  • <cfset strTest = (
  • "I like girls that weigh " &
  • NumberFormat( intI, "000" ) &
  • " lbs."
  • ) />
  •  
  • <!--- Check to see if the statements match up. --->
  • #YesNoFormat(
  • strStatement.EqualsIgnoreCase( strTest )
  • )#
  •  
  • </cfloop>
  •  
  • </cftimer>

I was surprised by the results. The ColdFusion Compare() method outperformed all the Java methods. Remember though, we are talking 5000 iterations here. At low iterations, they all perform lightening fast. Here is trending order of speed:

  1. Compare()
  2. String::Equals()
  3. String::EqualsIgnoreCase()
  4. String::CompareTo()

The fact that CompareTo() was the slowest and Compare() was the fastest is a bit surprising. I assume one would be built on the other. The only reason I can hazard a guess at this is because CompareTo() can take either an object or a string, and the type conversion is throwing it off. But, then again, on the other hand, Equals() takes only and object and performs well. I wanted to test EqualsNoCase() because it ONLY takes a string and I wanted to see what that did for performance. I think though, any performance boost it got from the string parameter is counter-acted by the fact that it is not case sensitive.

One reason why I wanted to test this AT ALL is the fact that seeing "NOT Compare()" for equality is not that user friendly. I was hoping that Equals() would be faster since it is nicer to look at. However, now that I think about it, I should be using JavaCast() for all of these, which adds some readability issues. I guess it was just a fun test to do.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page





Reader Comments

Dec 6, 2006 at 3:17 AM // reply »
1 Comments

Student loan consolidation, private student loans, free scholarship search engine, daily student loan blog, and more. - Lock in the lowest rate with NextStudent.


Jun 6, 2007 at 6:20 PM // reply »
3 Comments

Cool man thanks for taking the time to do this - I am in a project where I'm going to be manipulating strings from a db based on replace rules and I need to do a comparison once the manipulation/rules have been run on the database strings - then if the values are not the same as the origional, then I update the updated string to the db -
I was debating on what function to use and was leaning towards compare() as it was - this solidified it!


Dec 25, 2007 at 3:36 PM // reply »
125 Comments

I just stumbled across this though google and thought I'd shed some light on it. The reason the CF method is faster is because when you call a Java method in CF it uses reflection to call the method... which is quite expensive.

In fact, what CF really does is call java.lang.Class#getMethods() [1], do a search through the result to find a matching name and then try and match up the types of the arguments. It does cache the match result so subsequent calls are faster, but there's definitely overhead from doing a method call like this.

On the other hand CF's Compare function might look like this in Java:

public int Compare( String a, String b ) {
int r = a.compareTo( b );
if( r > 0 ) return 1;
return r == 0 ? 0 : -1;
}

So it should definitely be faster than doing a lookup for the method.

Things have gotten a lot faster over the years though in the Java world... [2]. :) Shame there's such a horrible class loader issue in Java 1.6 :/

[1] http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getMethods()
[2] http://www.jguru.com/faq/view.jsp?EID=246569


Dec 26, 2007 at 7:09 AM // reply »
6,516 Comments

@Elliott,

Thanks for the insight. Yeah, I have read a few really bad things about the Class Loader in Java 1.6. It seems like with CF8, a lot of people are going with Java 1.5. At least, that's what I think I've read.


Apr 1, 2009 at 10:37 AM // reply »
5 Comments

Ben,

Is there a way in Coldfusion to do a SQL like comparison?

For example, I have a webform that has a ID drop down - the iD looks something like this "AC1200" or "PR1982" etc.

Now what i wanna do is look at the first 2 characters of the ID, and based on that, enter a certain value in a column in the DB. SO that every time a "AC" appears in the ID, I should enter a specific value. Similarly, for each "PR..." entry, I want another value.

I know we can do a "WHERE Var LIKE AC%" comparison in SQL, but not totally sure if and/or how that can be done in CF!


Apr 1, 2009 at 10:43 AM // reply »
6,516 Comments

@UMTerp,

You can use REFind() for this:

<cfif REFind( "^AC", variable )> ... </cfif>

The RE = "regular expression". The "^" signifies the beginning of the string. So ^AC matches "AC" as the first part of the string.


Apr 1, 2009 at 11:28 AM // reply »
25 Comments

You can also use the Left() function to get the first 2 characters of the term - even trim it first then use Left(string,count).


Apr 1, 2009 at 11:37 AM // reply »
5 Comments

@Ben Nadel,

Great, it worked!! You got unbelievable reply speed! - within 6 mins of my query!!

Thanks!


Apr 1, 2009 at 11:38 AM // reply »
6,516 Comments

@UMTerp,

Ha ha, glad to help.

@Kevin,

Using left is good also.


May 12, 2009 at 9:36 AM // reply »
2 Comments

This is why I hate coldfusion. It doesn't hold to any conventions about how objects should be compared. For example, strings of different lengths get evaluated completely differently. I know of no other language that does this.

<cfscript>
a = '12345';
b = '12346';
// Should be false, and is false.
writeoutput('a eq b == #a eq b#<br />');

a = '2707200116272368271111';
b = '2707200116272368279465';
// Should be false, but isn't.
writeoutput('a eq b == #a eq b#<br />');
</cfscript>


May 12, 2009 at 8:02 PM // reply »
5 Comments

@Chris, Ben and others,

Re. Chris's comment about the difference in comparison results, could anyone explain why that is happening?


May 21, 2009 at 8:36 AM // reply »
6,516 Comments

@UMTerp,

My guess is that the strings that @Chris is comparing in the latter example are being converted to numbers for the comparison and the numbers that large cannot be compared well. As such, they get truncated and their truncations happen to be equal.

If you change the strings to have a preceeding, non-numeric value:

a = '_2707200116272368271111';
b = '_2707200116272368279465';

... then they are NOT equal. So, something is happen when it tries to convert them to numbers.

I've personally never had to deal with numbers this large, so it's never caused a problem. But, if you don't know why its happening, you can pull your hair out trying to debug this!


May 21, 2009 at 8:37 AM // reply »
6,516 Comments

@UMTerp,

Incidentally, if you use the Compare() function, this works with strings explicitly:

#NOT Compare( a, b )# == NO

.. which is what we expect.


May 22, 2009 at 7:20 AM // reply »
2 Comments

The most recent part of this discussion was also carried on over in the Railo group. Figure I would post a link for those interested.

http://groups.google.com/group/railo/browse_thread/thread/2b326e81c8e5e399?hl=en


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 22, 2009 at 1:56 AM
Learning ColdFusion 9: Using CFQuery In CFScript Can Enable SQL Injection Attacks
Why adobe would give you script equivalent of cfquery is beyond me. I love cfquery tag because it helps me wriite clean sql, and get away from the horrible jdbc queries If I wanted to write javali ... read »
Nov 22, 2009 at 1:45 AM
Streaming Text Using ColdFusion's CFContent Tag And The Variable Attribute
The reason you would want to do this is to stream. Ack json/xml files to ria clients I used thus technique before because putting json in response stream causes debugging info to come thru As well a ... read »
Nov 21, 2009 at 6:47 PM
Hal Helms - Real World Object Oriented Development, Sarasota - Day Five
@charlie griefer, Thank you.. ... read »
Nov 21, 2009 at 5:15 PM
Using ColdFusion Structures To Remove Duplicate List Values
@Jose Galdamez, Oh heh yeah I didn't paste the whole code. I should have defined the vars -- my bad. It's fixed thou. Thanks. ... read »
Nov 21, 2009 at 4:49 PM
Styling The ColdFusion 8 WriteToBrowser CFImage Output
Great work yet again Ben! Whilst I didn't use this whole code, I copied some of your regex code for a similar problem with the lack of an alt attribute and unescaped ampersands in CFIMAGE for Railo 3 ... read »
Nov 21, 2009 at 1:13 PM
My First ColdFusion Builder Extension - Encrypting And Decrypting CFM / CFC Files
@Ben, Because I am pedantic, I just want to make sure that everyone knows there is absolutely no encryption going on. There is only encoding and obfuscation. The cfencode tool only obfuscates your C ... read »
Nov 21, 2009 at 12:28 PM
Using ColdFusion Structures To Remove Duplicate List Values
@Jody I can't seem to get your code sample to work. If you are still having problems, try this code out and see if it gets you what you wanted. <!--- Comma delimited list with various duplicates ... read »
Nov 21, 2009 at 11:03 AM
Groovy Operator Overloading Does Not Work In The ColdFusion Context
Hi Ben, Thanks for this informative post. Now I am reading ur old posts too ... read »