From c9b27af64f41cc4fd06ee41a0faaca867e3cba4e Mon Sep 17 00:00:00 2001 From: Marten Deinum Date: Tue, 17 Nov 2020 11:52:58 +0100 Subject: [PATCH] Reduce overhead of char[] creation There are more locations which could benefit from not using a toCharArray on a String, but rather use the charAt method from the String itself. This to prevent an additional copy of the char[] being created. --- .../aop/aspectj/AspectJAdviceParameterNameDiscoverer.java | 4 ++-- .../main/java/org/springframework/core/Conventions.java | 8 ++++---- .../java/org/springframework/http/ContentDisposition.java | 3 ++- .../java/org/springframework/http/ResponseCookie.java | 3 +-- .../springframework/http/server/DefaultPathContainer.java | 6 +----- .../web/util/HierarchicalUriComponents.java | 3 ++- .../java/org/springframework/web/util/UriComponents.java | 3 ++- .../web/util/pattern/LiteralPathElement.java | 7 +++---- .../web/util/pattern/SingleCharWildcardedPathElement.java | 7 +++---- 9 files changed, 20 insertions(+), 24 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java index ec58afb296..be072a1a58 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java @@ -475,8 +475,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) && Character.isLowerCase(candidateToken.charAt(0))) { - char[] tokenChars = candidateToken.toCharArray(); - for (char tokenChar : tokenChars) { + for (int i = 1; i < candidateToken.length(); i++) { + char tokenChar = candidateToken.charAt(i); if (!Character.isJavaIdentifierPart(tokenChar)) { return null; } diff --git a/spring-core/src/main/java/org/springframework/core/Conventions.java b/spring-core/src/main/java/org/springframework/core/Conventions.java index 691f1811a8..70daea7b45 100644 --- a/spring-core/src/main/java/org/springframework/core/Conventions.java +++ b/spring-core/src/main/java/org/springframework/core/Conventions.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -225,11 +225,11 @@ public final class Conventions { if (!attributeName.contains("-")) { return attributeName; } - char[] chars = attributeName.toCharArray(); - char[] result = new char[chars.length -1]; // not completely accurate but good guess + char[] result = new char[attributeName.length() -1]; // not completely accurate but good guess int currPos = 0; boolean upperCaseNext = false; - for (char c : chars) { + for (int i = 0; i < attributeName.length(); i++ ) { + char c = attributeName.charAt(i); if (c == '-') { upperCaseNext = true; } diff --git a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java index 8b735a22ee..ce75abdc09 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java @@ -485,7 +485,8 @@ public final class ContentDisposition { } boolean escaped = false; StringBuilder sb = new StringBuilder(); - for (char c : filename.toCharArray()) { + for (int i = 0; i < filename.length() ; i++) { + char c = filename.charAt(i); if (!escaped && c == '"') { sb.append("\\\""); } diff --git a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java index 05ea8d372f..01048cab83 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseCookie.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseCookie.java @@ -386,9 +386,8 @@ public final class ResponseCookie extends HttpCookie { start = 1; end--; } - char[] chars = value.toCharArray(); for (int i = start; i < end; i++) { - char c = chars[i]; + char c = value.charAt(i); if (c < 0x21 || c == 0x22 || c == 0x2c || c == 0x3b || c == 0x5c || c == 0x7f) { throw new IllegalArgumentException( "RFC2616 cookie value cannot have '" + c + "'"); diff --git a/spring-web/src/main/java/org/springframework/http/server/DefaultPathContainer.java b/spring-web/src/main/java/org/springframework/http/server/DefaultPathContainer.java index 4476df7391..ddea35fc75 100644 --- a/spring-web/src/main/java/org/springframework/http/server/DefaultPathContainer.java +++ b/spring-web/src/main/java/org/springframework/http/server/DefaultPathContainer.java @@ -232,8 +232,6 @@ final class DefaultPathContainer implements PathContainer { private final String valueToMatch; - private final char[] valueToMatchAsChars; - private final MultiValueMap parameters; @@ -243,7 +241,6 @@ final class DefaultPathContainer implements PathContainer { DefaultPathSegment(String value, String valueToMatch, MultiValueMap params) { this.value = value; this.valueToMatch = valueToMatch; - this.valueToMatchAsChars = valueToMatch.toCharArray(); this.parameters = CollectionUtils.unmodifiableMultiValueMap(params); } @@ -254,7 +251,6 @@ final class DefaultPathContainer implements PathContainer { this.value = value; this.valueToMatch = value.contains(separator.encodedSequence()) ? value.replaceAll(separator.encodedSequence(), separator.value()) : value; - this.valueToMatchAsChars = this.valueToMatch.toCharArray(); this.parameters = EMPTY_PARAMS; } @@ -271,7 +267,7 @@ final class DefaultPathContainer implements PathContainer { @Override public char[] valueToMatchAsChars() { - return this.valueToMatchAsChars; + return this.valueToMatch.toCharArray(); } @Override diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index 6a28854714..37633018a9 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -791,7 +791,8 @@ final class HierarchicalUriComponents extends UriComponents { clear(this.currentLiteral); clear(this.currentVariable); clear(this.output); - for (char c : source.toCharArray()) { + for (int i = 0; i < source.length(); i++) { + char c = source.charAt(i); if (c == '{') { level++; if (level == 1) { diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponents.java b/spring-web/src/main/java/org/springframework/web/util/UriComponents.java index b197cd9e55..ea047e631a 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponents.java @@ -278,7 +278,8 @@ public abstract class UriComponents implements Serializable { int level = 0; int lastCharIndex = 0; char[] chars = new char[source.length()]; - for (char c : source.toCharArray()) { + for (int i = 0; i < source.length(); i++) { + char c = source.charAt(i); if (c == '{') { level++; } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java index 715831f700..224d5d7217 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 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. @@ -69,10 +69,9 @@ class LiteralPathElement extends PathElement { return false; } - char[] data = ((PathContainer.PathSegment)element).valueToMatchAsChars(); if (this.caseSensitive) { for (int i = 0; i < this.len; i++) { - if (data[i] != this.text[i]) { + if (value.charAt(i) != this.text[i]) { return false; } } @@ -80,7 +79,7 @@ class LiteralPathElement extends PathElement { else { for (int i = 0; i < this.len; i++) { // TODO revisit performance if doing a lot of case insensitive matching - if (Character.toLowerCase(data[i]) != this.text[i]) { + if (Character.toLowerCase(value.charAt(i)) != this.text[i]) { return false; } } diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java index 717a7c4a97..7aa748af6f 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/SingleCharWildcardedPathElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 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. @@ -74,11 +74,10 @@ class SingleCharWildcardedPathElement extends PathElement { return false; } - char[] data = ((PathSegment)element).valueToMatchAsChars(); if (this.caseSensitive) { for (int i = 0; i < this.len; i++) { char ch = this.text[i]; - if ((ch != '?') && (ch != data[i])) { + if ((ch != '?') && (ch != value.charAt((i)))) { return false; } } @@ -87,7 +86,7 @@ class SingleCharWildcardedPathElement extends PathElement { for (int i = 0; i < this.len; i++) { char ch = this.text[i]; // TODO revisit performance if doing a lot of case insensitive matching - if ((ch != '?') && (ch != Character.toLowerCase(data[i]))) { + if ((ch != '?') && (ch != Character.toLowerCase(value.charAt(i)))) { return false; } }