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  |  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 »
129 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 »
7,539 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 »
7,539 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 »
7,539 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 »
7,539 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 »
7,539 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
Mar 18, 2010 at 10:28 PM
Posting XML SOAP Requests With jQuery
can you please point me to the jquery documentation on the following # // Create our SOAP body content based off of # // the template. # var soapBody = soapTemplate.html().replace( # new RegExp( "\\ ... read »
Mar 18, 2010 at 6:34 PM
Exploring ColdFusion Component Runtime Class Properties And Serialization
@Ben Very useful analyses. Thank you @Elliot Thanks for additional clarification Though, it's quite a shame that getBust() failed...not defined ;) ... read »
Mar 18, 2010 at 5:35 PM
Exploring ColdFusion Component Runtime Class Properties And Serialization
Saving private properties is necessary so that you can "reconstitute" an object on the other side of the wire, or load up a serialized object you saved to disk. If it didn't save the private state o ... read »
Mar 18, 2010 at 4:04 PM
jQuery's Event Triggering, Order Of Default Behavior, And triggerHandler()
Tks! You saved-me today. it can be chained into one statement: $("#x).attr("checked","checked").triggerHandler('click'); ... read »
Mar 18, 2010 at 1:18 PM
Finally Finished Ayn Rand's Atlas Shrugged Audio Book
@joaopft, Not disputing what you say - but... If I understand you correctly, you are saying that Positivism is based on sense experience (what I experience is what is), but Quantum theory states tha ... read »
Mar 18, 2010 at 11:48 AM
Duplicate() Much Faster Than ColdFusion Query-of-Queries
I am working on a massive xml parsing, qofq app to create 2 seperate xml files. I just don't understand the concept/purpose of duplicate function, are you duplicating the data or the row, into a new ... read »
Mar 18, 2010 at 11:22 AM
Exploring ColdFusion Component Runtime Class Properties And Serialization
@Zarko, Ha ha, you know ColdFusion is my first love ;) ... read »
Mar 18, 2010 at 11:15 AM
Exploring ColdFusion Component Runtime Class Properties And Serialization
Hi Ben, nice to have you back! I already gave up on you, thinking you'll write about jQuery and iPhone for the rest our our lives! :) ... read »