Avoid LinkedList performance issues through use of ArrayDeque

Closes gh-25652
This commit is contained in:
Juergen Hoeller
2020-08-27 14:14:08 +02:00
parent 60fa704f78
commit 589060d10f
3 changed files with 34 additions and 28 deletions

View File

@@ -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.
@@ -20,8 +20,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import org.springframework.lang.Nullable;
@@ -31,7 +32,7 @@ import org.springframework.lang.Nullable;
* its sibling {@link ResizableByteArrayOutputStream}.
*
* <p>Unlike {@link java.io.ByteArrayOutputStream}, this implementation is backed
* by a {@link java.util.LinkedList} of {@code byte[]} instead of 1 constantly
* by an {@link java.util.ArrayDeque} of {@code byte[]} instead of 1 constantly
* resizing {@code byte[]}. It does not copy buffers when it gets expanded.
*
* <p>The initial buffer is only created when the stream is first written.
@@ -50,7 +51,7 @@ public class FastByteArrayOutputStream extends OutputStream {
// The buffers used to store the content bytes
private final LinkedList<byte[]> buffers = new LinkedList<>();
private final Deque<byte[]> buffers = new ArrayDeque<>();
// The size, in bytes, to use when allocating the first byte[]
private final int initialBlockSize;
@@ -289,7 +290,7 @@ public class FastByteArrayOutputStream extends OutputStream {
}
/**
* Create a new buffer and store it in the LinkedList
* Create a new buffer and store it in the ArrayDeque.
* <p>Adds a new buffer that can store at least {@code minCapacity} bytes.
*/
private void addBuffer(int minCapacity) {

View File

@@ -18,14 +18,15 @@ package org.springframework.util;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
@@ -655,6 +656,9 @@ public abstract class StringUtils {
* inner simple dots.
* <p>The result is convenient for path comparison. For other uses,
* notice that Windows separators ("\") are replaced by simple slashes.
* <p><strong>NOTE</strong> that {@code cleanPath} should not be depended
* upon in a security context. Other mechanisms should be used to prevent
* path-traversal issues.
* @param path the original path
* @return the normalized path
*/
@@ -690,7 +694,7 @@ public abstract class StringUtils {
}
String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);
LinkedList<String> pathElements = new LinkedList<>();
Deque<String> pathElements = new ArrayDeque<>();
int tops = 0;
for (int i = pathArray.length - 1; i >= 0; i--) {
@@ -709,7 +713,7 @@ public abstract class StringUtils {
}
else {
// Normal path element found.
pathElements.add(0, element);
pathElements.addFirst(element);
}
}
}
@@ -720,11 +724,11 @@ public abstract class StringUtils {
}
// Remaining top paths need to be retained.
for (int i = 0; i < tops; i++) {
pathElements.add(0, TOP_PATH);
pathElements.addFirst(TOP_PATH);
}
// If nothing else left, at least explicitly point to current path.
if (pathElements.size() == 1 && pathElements.getLast().isEmpty() && !prefix.endsWith(FOLDER_SEPARATOR)) {
pathElements.add(0, CURRENT_PATH);
pathElements.addFirst(CURRENT_PATH);
}
return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);