Author: bayard Date: Sun Sep 6 22:56:09 2009 New Revision: 811944 URL: http://svn.apache.org/viewvc?rev=811944&view=rev Log: Applying Stefan Zeller's performance improvement to StrBuilder (LANG-523) by doubling the size of the String in ensureCapacity. Tests indicate a hundredhold improvement in appending speed, which seems worth the doubling of data size.
Modified: commons/proper/lang/trunk/src/java/org/apache/commons/lang/Validate.java commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/StrBuilder.java Modified: commons/proper/lang/trunk/src/java/org/apache/commons/lang/Validate.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/apache/commons/lang/Validate.java?rev=811944&r1=811943&r2=811944&view=diff ============================================================================== --- commons/proper/lang/trunk/src/java/org/apache/commons/lang/Validate.java (original) +++ commons/proper/lang/trunk/src/java/org/apache/commons/lang/Validate.java Sun Sep 6 22:56:09 2009 @@ -16,6 +16,7 @@ */ package org.apache.commons.lang; +import java.text.MessageFormat; import java.util.Collection; import java.util.Iterator; import java.util.Map; @@ -31,10 +32,74 @@ * Validate.notNull( surname, "The surname must not be null"); * </pre> * + * All validate functions exist in 4 variants: + * + * <p>1st function with only the validation option</p> + * <pre> + * Validate.isNotNull(surName); + * </pre> + * + * <p>2nd function with an additional String message parameter. This should + * be used only if no additional parameters have to be provided. Instead of using + * String operations to create the message String, the following 3rd variant + * should be used.</p> + * <pre> + * Validate.isNotNull(surName, "surname must be set"); + * </pre> + * + * <p>Since commons-lang-3.0, for each validation function a similar 3rd validation function exists + * with a list of additional message parameters as Objects in ellipsis notation. + * This is used instead of simply passing a message String due to performance reasons! + * When using a message string, all parameters would have to be string concatenated + * before the call, even if no problem arises which would cost performance.</br> + * Instead of this, we will concatenate (with spaces) all given msgObjects.toString() + * only in case of a failed validation! If the first parameter of the msgObject is a + * String, it will be taken as the format string for {...@code MessageFormat}.</p> + * + * <h3>Examples:</h3> + * <p> + * Simply validating an Argument without further message: + * <pre> + * public void myFn(String argString, Integer argInt) { + * Validate.notNull(argString); + * Validate.notNull(argInt); + * Validate.isTrue(argInt.intValue > 3); + * } + * </pre> + * <p> + * + * <p> + * Validating an Argument and adding a message to the IllegalArgumentException: + * <pre> + * public void myFn(String argString, Integer argInt) { + * Validate.notNull(argInt, "Integer parameter must be set); + * Validate.isTrue(argInt.intValue > 3, "Integer parameter must be <=3!"); + * } + * </pre> + * <p> + * + * <p> + * If the first parameter of the msgObject is a String {...@code MessageFormat} will be used: + * <pre> + * Validate.isTrue(argInt1.intValue > argInt2.intValue, "param2 actually is {1} but must larger than param1 {0} !", argInt1, argInt2); + * </pre> + * </p> + * + * <p>The same function sometimes exists multiple times in a 4th form with a single message String parameter + * and an additional value parameter. This is essentially the same like the 3rd form, but with fixed + * object values to preserve backward compatibility with Validate 2.0!<p> + * <p>If the message String contains a <code>"{0}"</code>, it will be passed to + * {...@code MessageFormat} with the value parameter as single Object parameter. If not, the value parameter + * will simply get concatenated to the message String separated with a space. + * </p> + + * @see MessageFormat + * * @author <a href="mailto:ola.b...@arkitema.se">Ola Berg</a> * @author Stephen Colebourne * @author Gary Gregory * @author Norm Deane + * @author <a href="mailto:strub...@yahoo.de">Mark Struberg</a> * @since 2.0 * @version $Id$ */ @@ -74,7 +139,7 @@ */ public static void isTrue(boolean expression, String message, Object value) { if (expression == false) { - throw new IllegalArgumentException(message + value); + throw new IllegalArgumentException(getMessage(message, value)); } } @@ -100,7 +165,8 @@ */ public static void isTrue(boolean expression, String message, long value) { if (expression == false) { - throw new IllegalArgumentException(message + value); + + throw new IllegalArgumentException(getMessage(message, value)); } } @@ -127,7 +193,7 @@ */ public static void isTrue(boolean expression, String message, double value) { if (expression == false) { - throw new IllegalArgumentException(message + value); + throw new IllegalArgumentException(getMessage(message, value)); } } @@ -182,6 +248,32 @@ } } + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the test result is <code>false</code>.</p> + * + * <p>This is used when validating according to an arbitrary boolean expression, + * such as validating a primitive number or using your own custom validation + * expression.</p> + * + * <pre> + * Validate.isTrue(argInt1.intValue > argInt2.intValue, + * "param2 actually is {1} but must larger than param1 {0} !", argInt1, argInt2); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * @param expression a boolean expression + * @throws IllegalArgumentException if expression is <code>false</code> + */ + public static void isTrue(boolean expression, Object... msgObjects) { + if (expression == false) { + throw new IllegalArgumentException(getMessage(msgObjects)); + } + } + // notNull //--------------------------------------------------------------------------------- @@ -221,6 +313,28 @@ notNull(object, "The validated object is null"); } + + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument is <code>null</code>.</p> + * + * <pre> + * Validate.notNull(myObject, "This happens while processing user {0}, currentUser); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * @param object Object to validate + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + */ + public static void notNull(Object object, Object... msgObjects) { + if (object == null) { + throw new IllegalArgumentException(getMessage(msgObjects)); + } + } + // notEmpty array //--------------------------------------------------------------------------------- @@ -259,6 +373,26 @@ notEmpty(array, "The validated array is empty"); } + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument array is empty (<code>null</code> or no elements).</p> + * + * <pre> + * Validate.notEmpty(myArray, "This happens while processing user {0}, currentUser); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * @param array the array to check is not empty + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + * @throws IllegalArgumentException if the array is empty + */ + public static void notEmpty(Object[] array, Object... msgObjects) { + notEmpty(array, getMessage(msgObjects)); + } + // notEmpty collection //--------------------------------------------------------------------------------- @@ -297,6 +431,26 @@ notEmpty(collection, "The validated collection is empty"); } + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument Collection is empty (<code>null</code> or no elements).</p> + * + * <pre> + * Validate.notEmpty(myCollection, "This happens while processing user {0}, currentUser); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * @param collection the collection to check is not empty + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + * @throws IllegalArgumentException if the collection is empty + */ + public static void notEmpty(Collection<?> collection, Object... msgObjects) { + notEmpty(collection, getMessage(msgObjects)); + } + // notEmpty map //--------------------------------------------------------------------------------- @@ -335,6 +489,26 @@ notEmpty(map, "The validated map is empty"); } + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument Map is empty (<code>null</code> or no elements).</p> + * + * <pre> + * Validate.notEmpty(myMap, "This happens while processing user {0}, currentUser); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * @param map the map to check is not empty + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + * @throws IllegalArgumentException if the map is empty + */ + public static void notEmpty(Map<?,?> map, Object... msgObjects) { + notEmpty(map, getMessage(msgObjects)); + } + // notEmpty string //--------------------------------------------------------------------------------- @@ -373,6 +547,26 @@ notEmpty(string, "The validated string is empty"); } + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument String is empty (<code>null</code> or zero length).</p> + * + * <pre> + * Validate.notEmpty(myString); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * @param string the string to check is not empty + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + * @throws IllegalArgumentException if the string is empty + */ + public static void notEmpty(String string, Object... msgObjects) { + notEmpty(string, getMessage(msgObjects)); + } + // notNullElements array //--------------------------------------------------------------------------------- @@ -429,6 +623,36 @@ } } + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument array has <code>null</code> elements or is + * <code>null</code>.</p> + * + * <pre> + * Validate.noNullElements(myArray); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * <p>If the array is null then the message in the exception is 'The validated object is null'.</p> + * + * @param array the array to check + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + * @throws IllegalArgumentException if the array has <code>null</code> + * elements or is <code>null</code> + */ + public static void noNullElements(Object[] array, Object... msgObjects) { + Validate.notNull(array); + for (int i = 0; i < array.length; i++) { + if (array[i] == null) { + //X TODO maybe we can add 'i' as 0-th element? + throw new IllegalArgumentException(getMessage(msgObjects)); + } + } + } + // notNullElements collection //--------------------------------------------------------------------------------- @@ -487,6 +711,41 @@ /** * <p>Validate an argument, throwing <code>IllegalArgumentException</code> + * if the argument Collection has <code>null</code> elements or is + * <code>null</code>.</p> + * + * <pre> + * Validate.noNullElements(myCollection); + * </pre> + * + * <p>If the first msgObject is a String, the {...@code MessageFormat} will be used to construct the message</p> + * <p>Otherwise the message in the exception is 'Validation failed: ' followed by all given + * parameters delimited with spaces.</p> + * + * <p>If the collection is null then the message in the exception is 'The validated object is null'.</p> + * + * @param collection the collection to check + * @param msgObjects additional Objects added as text message to the InvalidArgumentException + * @throws IllegalArgumentException if the collection has + * <code>null</code> elements or is <code>null</code> + */ + public static void noNullElements(Collection collection, Object... msgObjects) { + Validate.notNull(collection); + int i = 0; + for (Iterator it = collection.iterator(); it.hasNext(); i++) { + if (it.next() == null) { + //X TODO how about adding 'i' as 0-th element? + throw new IllegalArgumentException(getMessage(msgObjects)); + } + } + } + + + // allElementsOfType collection + //--------------------------------------------------------------------------------- + + /** + * <p>Validate an argument, throwing <code>IllegalArgumentException</code> * if the argument collection is <code>null</code> or has elements that * are not of type <code>clazz</code> or a subclass.</p> * @@ -541,4 +800,74 @@ } } + /** + * <p> + * Validate an argument, throwing <code>IllegalArgumentException</code> if the argument collection is + * <code>null</code> or has elements that are not of type <code>clazz</code> or a subclass. + * </p> + * + * <pre> + * Validate.allElementsOfType(collection, String.class); + * </pre> + * + * <p> + * The message in the exception is 'The validated collection contains an element not of type clazz at index: '. + * </p> + * + * @param collection + * the collection to check, not null + * @param clazz + * the <code>Class</code> which the collection's elements are expected to be, not null + * @since 2.1 + */ + public static void allElementsOfType(Collection collection, Class clazz, Object... msgObjects) { + Validate.notNull(collection); + Validate.notNull(clazz); + int i = 0; + for (Iterator it = collection.iterator(); it.hasNext(); i++) { + if (clazz.isInstance(it.next()) == false) { + //X TODO how to add clazz.getName() and i? + throw new IllegalArgumentException(getMessage(msgObjects)); + } + } + } + + // private helper functions + //--------------------------------------------------------------------------------- + + + /** + * private helper function to create an error message from the given Objects + * If the first object in msgObjects is of type {...@code String} then + * {...@code MessageFormat} will be used to format the output message. + * + * @param msgObjects + * @return concatenated String representation of all the objects + */ + private static String getMessage(Object... msgObjects) { + if (msgObjects.length > 0 && msgObjects[0] instanceof String) { + String message = (String) msgObjects[0]; + if (msgObjects.length == 2 && !message.matches("[^\\{]*\\{\\d*\\}.*")) { + // if it doesn't contain {0}, {1} etc we simply use string concatenation + return message + msgObjects[1]; // no space between to act like original function! + } + + MessageFormat form = new MessageFormat((String) msgObjects[0]); + Object[] params = new Object[msgObjects.length - 1]; + System.arraycopy(msgObjects, 1, params, 0, msgObjects.length - 1); + return form.format(params); + } + else { + StringBuffer sb = new StringBuffer("Validation failed: ["); + for(int i = 0; i < msgObjects.length; i++) { + if (i > 0) { + sb.append(' '); + } + sb.append(msgObjects[i]); + } + sb.append(']'); + return sb.toString(); + } + } + } Modified: commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/StrBuilder.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/StrBuilder.java?rev=811944&r1=811943&r2=811944&view=diff ============================================================================== --- commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/StrBuilder.java (original) +++ commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/StrBuilder.java Sun Sep 6 22:56:09 2009 @@ -231,7 +231,7 @@ public StrBuilder ensureCapacity(int capacity) { if (capacity > buffer.length) { char[] old = buffer; - buffer = new char[capacity]; + buffer = new char[capacity * 2]; System.arraycopy(old, 0, buffer, 0, size); } return this;