From 11bac7c4e1903553a1e3b7411efc56dadd59234a Mon Sep 17 00:00:00 2001 From: Marten Deinum Date: Wed, 2 Dec 2020 20:00:31 +0100 Subject: [PATCH] Reduce the toCharArray overhead Both the PatternMatcher and JdbcParameterUtils use String.toCharArray for processing. This will create a new char[] which needs to be collected. The same code has been rewritten to use String.charAt to reduce the overhead. Additionally unneeded object creation in the PatternMatcher has been removed as well, to reduce further objects needed to be gc'ed. --- .../item/database/JdbcParameterUtils.java | 29 +++++------ .../batch/support/PatternMatcher.java | 48 ++++++++----------- 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcParameterUtils.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcParameterUtils.java index c0ceaf7d5..bf718117f 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcParameterUtils.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcParameterUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import java.util.List; * * @author Thomas Risberg * @author Juergen Hoeller + * @author Marten Deinum * @since 2.0 */ public class JdbcParameterUtils { @@ -53,30 +54,29 @@ public class JdbcParameterUtils { return 0; } - char[] statement = sql.toCharArray(); boolean withinQuotes = false; Map namedParameters = new HashMap<>(); char currentQuote = '-'; int parameterCount = 0; int i = 0; - while (i < statement.length) { + while (i < sql.length()) { if (withinQuotes) { - if (statement[i] == currentQuote) { + if (sql.charAt(i) == currentQuote) { withinQuotes = false; currentQuote = '-'; } } else { - if (statement[i] == '"' || statement[i] == '\'') { + if (sql.charAt(i) == '"' || sql.charAt(i) == '\'') { withinQuotes = true; - currentQuote = statement[i]; + currentQuote = sql.charAt(i); } else { - if (statement[i] == ':' || statement[i] == '&') { + if (sql.charAt(i) == ':' || sql.charAt(i) == '&') { int j = i + 1; StringBuilder parameter = new StringBuilder(); - while (j < statement.length && parameterNameContinues(statement, j)) { - parameter.append(statement[j]); + while (j < sql.length() && parameterNameContinues(sql, j)) { + parameter.append(sql.charAt(j)); j++; } if (j - i > 1) { @@ -88,7 +88,7 @@ public class JdbcParameterUtils { } } else { - if (statement[i] == '?') { + if (sql.charAt(i) == '?') { parameterCount++; } } @@ -108,10 +108,11 @@ public class JdbcParameterUtils { * @param statement the SQL statement * @param pos the position within the statement */ - private static boolean parameterNameContinues(char[] statement, int pos) { - return (statement[pos] != ' ' && statement[pos] != ',' && statement[pos] != ')' && - statement[pos] != '"' && statement[pos] != '\'' && statement[pos] != '|' && - statement[pos] != ';' && statement[pos] != '\n' && statement[pos] != '\r'); + private static boolean parameterNameContinues(String statement, int pos) { + char character = statement.charAt(pos); + return (character != ' ' && character != ',' && character != ')' && + character != '"' && character != '\'' && character != '|' && + character != ';' && character != '\n' && character != '\r'); } } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java index 06f6bd168..f692a2550 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007 the original author or authors. + * Copyright 2006-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,7 @@ package org.springframework.batch.support; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -27,11 +25,12 @@ import org.springframework.util.Assert; /** * @author Dave Syer * @author Dan Garrette + * @author Marten Deinum */ public class PatternMatcher { - private Map map = new HashMap<>(); - private List sorted = new ArrayList<>(); + private final Map map; + private final List sorted; /** * Initialize a new {@link PatternMatcher} with a map of patterns to values @@ -42,14 +41,7 @@ public class PatternMatcher { this.map = map; // Sort keys to start with the most specific sorted = new ArrayList<>(map.keySet()); - Collections.sort(sorted, new Comparator() { - @Override - public int compare(String o1, String o2) { - String s1 = o1; // .replace('?', '{'); - String s2 = o2; // .replace('*', '}'); - return s2.compareTo(s1); - } - }); + sorted.sort(Comparator.reverseOrder()); } /** @@ -66,12 +58,10 @@ public class PatternMatcher { * false otherwise. */ public static boolean match(String pattern, String str) { - char[] patArr = pattern.toCharArray(); - char[] strArr = str.toCharArray(); int patIdxStart = 0; - int patIdxEnd = patArr.length - 1; + int patIdxEnd = pattern.length() - 1; int strIdxStart = 0; - int strIdxEnd = strArr.length - 1; + int strIdxEnd = str.length() - 1; char ch; boolean containsStar = pattern.contains("*"); @@ -82,9 +72,9 @@ public class PatternMatcher { return false; // Pattern and string do not have the same size } for (int i = 0; i <= patIdxEnd; i++) { - ch = patArr[i]; + ch = pattern.charAt(i); if (ch != '?') { - if (ch != strArr[i]) { + if (ch != str.charAt(i)) { return false;// Character mismatch } } @@ -97,9 +87,9 @@ public class PatternMatcher { } // Process characters before first star - while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { + while ((ch = pattern.charAt(patIdxStart)) != '*' && strIdxStart <= strIdxEnd) { if (ch != '?') { - if (ch != strArr[strIdxStart]) { + if (ch != str.charAt(strIdxStart)) { return false;// Character mismatch } } @@ -110,7 +100,7 @@ public class PatternMatcher { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { + if (pattern.charAt(i) != '*') { return false; } } @@ -118,9 +108,9 @@ public class PatternMatcher { } // Process characters after last star - while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { + while ((ch = pattern.charAt(patIdxEnd)) != '*' && strIdxStart <= strIdxEnd) { if (ch != '?') { - if (ch != strArr[strIdxEnd]) { + if (ch != str.charAt(strIdxEnd)) { return false;// Character mismatch } } @@ -131,7 +121,7 @@ public class PatternMatcher { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { + if (pattern.charAt(i) != '*') { return false; } } @@ -143,7 +133,7 @@ public class PatternMatcher { while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { - if (patArr[i] == '*') { + if (pattern.charAt(i) == '*') { patIdxTmp = i; break; } @@ -160,9 +150,9 @@ public class PatternMatcher { int foundIdx = -1; strLoop: for (int i = 0; i <= strLength - patLength; i++) { for (int j = 0; j < patLength; j++) { - ch = patArr[patIdxStart + j + 1]; + ch = pattern.charAt(patIdxStart + j + 1); if (ch != '?') { - if (ch != strArr[strIdxStart + i + j]) { + if (ch != str.charAt(strIdxStart + i + j)) { continue strLoop; } } @@ -183,7 +173,7 @@ public class PatternMatcher { // All characters in the string are used. Check if only '*'s are left // in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { + if (pattern.charAt(i) != '*') { return false; } }