This is an automated email from the ASF dual-hosted git repository.

mawiesne pushed a commit to branch opennlp-2.x
in repository https://gitbox.apache.org/repos/asf/opennlp.git


The following commit(s) were added to refs/heads/opennlp-2.x by this push:
     new 07c6bca8 OPENNLP-1759: Optimize computation of hashCode in StringList 
(OpenNLP 2.x)
07c6bca8 is described below

commit 07c6bca85b326d18d3bd890c6ddb26b2dd565b28
Author: Martin Wiesner <[email protected]>
AuthorDate: Thu Jul 10 19:43:07 2025 +0200

    OPENNLP-1759: Optimize computation of hashCode in StringList (OpenNLP 2.x)
---
 .../main/java/opennlp/tools/util/StringList.java   | 31 ++++++++--------------
 .../uima/dictionary/DictionaryResourceTest.java    | 20 +++++++-------
 2 files changed, 20 insertions(+), 31 deletions(-)

diff --git a/opennlp-tools/src/main/java/opennlp/tools/util/StringList.java 
b/opennlp-tools/src/main/java/opennlp/tools/util/StringList.java
index 004292bd..8ceedb5a 100644
--- a/opennlp-tools/src/main/java/opennlp/tools/util/StringList.java
+++ b/opennlp-tools/src/main/java/opennlp/tools/util/StringList.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 import opennlp.tools.util.jvm.StringInterners;
 
@@ -33,6 +34,9 @@ public class StringList implements Iterable<String> {
 
   private final boolean caseSensitive;
 
+  // It is safe to use caching of the hashCode for this class
+  private transient Integer hashCode = null; // initial value is uncomputed
+
   /**
    * Initializes a {@link StringList} instance. By default, this instance is 
case-sensitive.
    * <p>
@@ -53,7 +57,7 @@ public class StringList implements Iterable<String> {
    *
    * @param tokens The string parts of the new {@link StringList}.
    *               Must not be an empty tokens array or {@code null}.
-   *               
+   *
    * @throws IllegalArgumentException Thrown if parameters were invalid.
    */
   public StringList(String... tokens) {
@@ -73,7 +77,6 @@ public class StringList implements Iterable<String> {
    * @throws IllegalArgumentException Thrown if parameters were invalid.
    */
   public StringList(boolean isCaseSensitive, String... tokens) {
-
     Objects.requireNonNull(tokens, "tokens must not be null");
 
     if (tokens.length == 0) {
@@ -81,7 +84,6 @@ public class StringList implements Iterable<String> {
     }
 
     this.tokens = new String[tokens.length];
-
     for (int i = 0; i < tokens.length; i++) {
       this.tokens[i] = StringInterners.intern(tokens[i]);
     }
@@ -161,8 +163,11 @@ public class StringList implements Iterable<String> {
 
   @Override
   public int hashCode() {
-    // if lookup is too slow optimize this
-    return StringUtil.toLowerCase(toString()).hashCode();
+    if (hashCode == null) {
+      // compute once and cache to safe CPU cycles during use
+      this.hashCode = StringUtil.toLowerCase(String.join(",", 
tokens)).hashCode();
+    }
+    return hashCode;
   }
 
   @Override
@@ -184,21 +189,7 @@ public class StringList implements Iterable<String> {
    */
   @Override
   public String toString() {
-    StringBuilder string = new StringBuilder();
-
-    string.append('[');
-
-    for (int i = 0; i < size(); i++) {
-      string.append(getToken(i));
-
-      if (i < size() - 1) {
-        string.append(',');
-      }
-    }
-
-    string.append(']');
-
-    return string.toString();
+    return Arrays.stream(tokens).collect(Collectors.joining(",", "[", "]"));
   }
 
   /**
diff --git 
a/opennlp-uima/src/test/java/opennlp/uima/dictionary/DictionaryResourceTest.java
 
b/opennlp-uima/src/test/java/opennlp/uima/dictionary/DictionaryResourceTest.java
index 9f1804b0..846e8c67 100644
--- 
a/opennlp-uima/src/test/java/opennlp/uima/dictionary/DictionaryResourceTest.java
+++ 
b/opennlp-uima/src/test/java/opennlp/uima/dictionary/DictionaryResourceTest.java
@@ -38,6 +38,7 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
+import opennlp.tools.dictionary.Dictionary;
 import opennlp.tools.util.StringList;
 import opennlp.uima.AbstractTest;
 import opennlp.uima.util.CasUtil;
@@ -69,17 +70,14 @@ public class DictionaryResourceTest extends AbstractTest {
   public void testDictionaryWasLoaded() {
 
     try {
-      DictionaryResource dic = (DictionaryResource) AE.getResourceManager()
-          .getResource("/opennlp.uima.Dictionary");
-      // simple check if ordering always is the same...
-      Assertions.assertEquals(
-          "[[Berlin], [Stockholm], [New,York], [London], [Copenhagen], 
[Paris]]",
-          dic.getDictionary().toString());
-      // else we can do a simple test like this
-      Assertions.assertEquals(6,
-          dic.getDictionary().asStringSet().size(), "There should be six 
entries in the dictionary");
-      Assertions.assertTrue(dic.getDictionary().contains(new 
StringList("London")),
-          "London should be in the dictionary");
+      final DictionaryResource dic = (DictionaryResource) 
AE.getResourceManager()
+              .getResource("/opennlp.uima.Dictionary");
+      final Dictionary d = dic.getDictionary();
+      Assertions.assertNotNull(d);
+      Assertions.assertEquals(6, d.asStringSet().size(),
+              "There should be six entries in the dictionary");
+      Assertions.assertTrue(d.contains(new StringList("London")),
+              "London should be in the dictionary");
     } catch (Exception e) {
       Assertions.fail("Dictionary was not loaded.");
     }

Reply via email to