📄 josqlcomparator.java
字号:
/* * Copyright 2004-2005 Gary Bentley * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.josql.utils;import java.util.List;import java.util.Comparator;import org.josql.Query;import org.josql.QueryParseException;import org.josql.QueryExecutionException;import org.josql.internal.ListExpressionComparator;/** * This class allows the ORDER BY clause of a JoSQL SQL clause to be used * as a Comparator. It should be noted that is the same as performing: {@link Query#execute(List)} * but there are times when having a separate comparator is desirable. * The EXECUTE ON ALL clause is supported but you must call: {@link #doExecuteOn(List)} * first to ensure that they are executed. * <p> * This class is basically just a thin wrapper around using the comparator gained by * calling: {@link Query#getOrderByComparator()}. * <p> * A note on performance, for small numbers of objects (around 1000) this comparator * has (for vanilla accessors, no function calls) pretty comparable performance against a * hand-coded Java Comparator that performs the same function. However start to scale the * numbers of objects and performance degrades, in testing for ~34000 FileWrapper objects * to order by: <code>path DESC, lastModified, name, length</code> took around: 1300ms. * The hand-coded Java Comparator took around: 180ms! The upshot is, if you need flexibility * and do not need to order large numbers of objects then use this kind of Comparator, if * performance and numbers of objects is an issue then hand-rolling your own Comparator * is probably best. As a side-note, to perform the following order by: * <code>lower(path) DESC, lastModified, name, length</code> using a JoSQLComparator took: * about: 1400ms. However modifying the hand-coded Comparator to use: * {@link String#compareToIgnoreCase(String)} then took about 860ms! And if you using: * {@link String#toLowerCase()} for each string instead, it then takes about: 1800ms! * (Meaning that in certain circumstances JoSQL can be faster!) * <p> * <h3>Caching</h3> * <p> * It is not uncommon for a Comparator (even using the effecient merge-sort implementation of * {@link java.util.Collections#sort(List,Comparator)}) to perform thousands (even millions!) * of comparisons.<br /><br /> * However since JoSQL does not automatically cache the results of calls to functions and * results of accessor accesses the performance of this kind of "dynamic" Comparator can * quickly degrade. To mitigate this it is possible to turn "caching" on whereby the * Comparator will "remember" the results of the functions on a per object basis and use those * values instead of calling them again. This is not without it's downside however. * Firstly since a reference to the object will be held it is important (if caching is used * that you call: {@link #clearCache()} once the Comparator has been used to free up those * references (it was considered using a {@link java.util.WeakHashMap} but that doesn't provide * exactly what's needed here).<br /><br /> * It is recommended that caching is turned on when the Comparator is to be used in a sort * operation , i.e. calling: {@link java.util.Collections#sort(List,Comparator)} or similar * (however careful consideration needs to be given to the amount of memory that this * may consume, i.e. 4 bytes = 1 object reference, plus 1 List, plus 4 bytes per order * by "column" it soon adds up)<br /><br /> * If the comparator is to be used in a {@link java.util.TreeMap} or {@link java.util.TreeSet} * then caching should not be used since the values may (and perhaps should) change over time * but due to caching the order won't change. * <p> * Last Modified By: $Author: barrygently $<br /> * Last Modified On: $Date: 2005/01/20 15:27:25 $<br /> * Current Revision: $Revision: 1.1 $<br /> */ public class JoSQLComparator implements Comparator{ private Query q = null; private Exception exp = null; private ListExpressionComparator c = null; /** * Execute the EXECUTE ON ALL expressions. * * @param l The list to execute the expressions on. */ public void doExecuteOn (List l) throws QueryExecutionException { this.q.doExecuteOn (l, Query.ALL); } /** * Clear the cache, it is VITAL that you call this method before you use * the comparator (if it has been used before) otherwise data objects will * be "left around" and preventing the GC from cleaning them up. */ public void clearCache () { if (this.q != null) { this.c.clearCache (); } } /** * Return whether this comparator uses caching to improve performance. * * @return <code>true</code> if caching is on. * @throws IllegalStateException If the query has not yet been parsed or set. */ public boolean isCaching () throws IllegalStateException { if ((this.q == null) || (!this.q.parsed ()) ) { throw new IllegalStateException ("Query has not yet been parsed."); } return this.c.isCaching (); } /** * Set whether the comparator should use caching to improve performance. * * @param b Set to <code>true</code> to turn caching on. * @throws IllegalStateException If the query has not yet been parsed or set. */ public void setCaching (boolean b) throws IllegalStateException { if ((this.q == null) || (!this.q.parsed ()) ) { throw new IllegalStateException ("Query has not yet been parsed."); } this.c.setCaching (b); } /** * Init this filter with the query. * * @param q The query. * @throws QueryParseException If there is an issue with the parsing of the query. */ public JoSQLComparator (String q) throws QueryParseException { this.setQuery (q); } /** * Compares the objects as according to the ORDER BY clause. * * @param o1 The first object. * @param o2 The second object. */ public int compare (Object o1, Object o2) { try { return c.ci (o1, o2); } catch (Exception e) { this.exp = e; return 0; } } /** * Init this file filter with the query already built and parsed. * * @param q The query. * @throws IllegalStateException If the Query object has not been parsed. * @throws QueryParseException If the FROM class is not as expected. */ public JoSQLComparator (Query q) throws IllegalStateException, QueryParseException { this.setQuery (q); } /** * The {@link Comparator#compare(Object,Object)} method does not allow for * any exceptions to be thrown however since the execution of the ORDER BY clause * on the objects can cause the throwing of a {@link QueryParseException} it should * be captured. If the exception is thrown then this method will return it. * * @return The exception thrown by the execution of the ORDER BY clause in {@link #compare(Object,Object)} * or by sub-class/interface specific methods, this may be null if no exception was thrown. */ public Exception getException () { return this.exp; } /** * Set a new Query (string form) for use in this filter. * * @param q The Query to use. * @throws QueryParseException If there is an issue with the parsing of the query, * or if the FROM class is not as expected. */ public void setQuery (String q) throws QueryParseException { this.q = new Query (); this.q.parse (q); this.c = (ListExpressionComparator) this.q.getOrderByComparator (); this.exp = null; } /** * Set a new Query object for use in this filter. * * @param q The Query to use. * @throws IllegalStateException If the Query object has not been parsed. * @throws QueryParseException If the FROM class is not as expected. */ public void setQuery (Query q) throws IllegalStateException, QueryParseException { if (!q.parsed ()) { throw new IllegalStateException ("Query has not yet been parsed."); } this.q = q; this.c = (ListExpressionComparator) this.q.getOrderByComparator (); this.exp = null; } /** * Get the Query we are using to process objects. * * @return The Query. */ public Query getQuery () { return this.q; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -