Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Eric Sosman Newsgroups: comp.lang.java.programmer Subject: Re: Why not String compare? Date: Thu, 1 Sep 2016 17:57:39 -0400 Organization: A noiseless patient Spider Lines: 84 Message-ID: References: <33463070-424f-4fb0-956b-2849f1a400eb@googlegroups.com> <855574dd-f21f-46f9-8972-a55aa189cf27@googlegroups.com> <1pr3rgydxxzp5.dlg@kimmeringer.de> Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Thu, 1 Sep 2016 21:57:53 -0000 (UTC) Injection-Info: mx02.eternal-september.org; posting-host="2d081e2f7155c28005d4472f67c2f43d"; logging-data="24563"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/q9X9VcJAVzh88T6OW/L0F" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 In-Reply-To: <1pr3rgydxxzp5.dlg@kimmeringer.de> Cancel-Lock: sha1:DrG8mC3/eKBPh2vZR72Mm6fs14Y= Xref: csiph.com comp.lang.java.programmer:35533 On 9/1/2016 2:42 PM, Lothar Kimmeringer wrote: > Eric Douglas wrote: > >> Not trying to reverse it, why would I need to reverse it? > > Maybe not you but the common use-case that uses compareTo > >> I have a TreeSet called records, and I do this. >> records.stream().filter(item -> item.getKey(currKnum).compareTo(currKey) > 0) >> >> The getKey() method of the objects in this TreeSet accepts an int and returns a (non-null)String. I want this filter to return all items. What better way than to pass in null as the value to compareTo? Shouldn't everything be greater than null? > > compareTo is commonly used for sorting data. So a.compareTo(b) > is called to decide what element should be sorted to "the left" > and what element should be sorted to "the right". What element > is a and b is dependent on the implementation of the sorting > algortithm and the actual data within the set. > > Allowing a.compareTo(null) to return something would lead to > non-deterministic behavior since the sort might succeed if by > chance null ends up being b all the time. But an optimization > of the sorting algorithm or a new element in the set might > lead to null end up as a and referencing null always leads to > a NPE. Throwing a NPE when compareTo is called with null as > parameter brings back the deterministic behavior and therefor > is declared as requirement for implementations of compareTo. Exactly: A Comparable must implement a /total order/ (see, for example, ). One of the defining characteristics of a total order is antisymmetry: The results of X.compareTo(Y) and Y.compareTo(X) must be opposite in sign, or both zero. If either is unable to deliver a result and throws an exception instead, so too must the other. This may seem odd, but it's really just "If one doesn't throw, then the other mustn't either" written the other way around. A Comparator has a bit more freedom. It must still implement a total order, but because neither of the compared items is `this' it is not obliged to throw NPE when one of them is null. (It is allowed to do so, of course, provided it does so consistently.) An algorithm using Comparable or a Comparator is "entitled" to rely on the fact that it is dealing with a total order, so it can deduce the outcome of a comparison not actually performed if other comparisons imply the result. A TreeMap, for example, can compare the search key to an item in the Map and know which branch to follow; it need not explore the ruled-out branch at all because it "knows" the results of all potential key-to-item comparisons in that branch without needing to make them. This "knowledge" flows directly from the properties of the total order; if the Comparable or Comparator does *not* implement a total order, what the algorithm "knows" may cause it to go innocently off the rails. ... but back to the O.P.'s problem: He wants to apply a filter to a stream of Strings, so he needs to give the filter() method a Predicate. He wrote a Predicate that exploits the fact that String implements Comparable, but this fails because his intended use involves theString.compareTo(null) which as we've seen above must be consistent with null.compareTo(theString). Since the Predicate as written won't do the job, he needs a different one. Three possibilities occur to me. Most directly: filter((item) -> currKey == null || item.getKey(currKnum).compareTo(currKey) > 0) Alternatively, let `currKey' be the least included element instead of the greatest excluded, using "" to mean "include everything": filter((item) -> item.getKey(currKnum).compareTo(currKey) >= 0) Finally, instead of using `currKnum' and `currKey' as the "globals" for the operation, he might instead use the Predicate: Predicate currPred = ...; filter(currPred) ... in which case "include everything" is just Predicate currPred = () -> true; -- esosman@comcast-dot-net.invalid The Tooth Fairy has gone high-tech, now pays in Bitecoin.