From 9c1efdc71540146031763af9b1c1b2d7d1e50566 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Wed, 23 May 2018 00:50:12 -0400 Subject: [PATCH] Optimize InListUtil.java --- .../moparisthebest/jdbc/util/InListUtil.java | 116 ++++++++++-------- .../java/com/moparisthebest/jdbc/InList.java | 6 +- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java b/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java index 0308db1..08788d1 100644 --- a/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java +++ b/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java @@ -1,86 +1,98 @@ package com.moparisthebest.jdbc.util; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; public class InListUtil { public static final int defaultMaxSize = Integer.parseInt(System.getProperty("QueryMapper.BindInList.defaultMaxSize", "999")); + public static final String inEmpty = "(0=1)", notInEmpty = "(1=1)"; - private static List> split(final List list, final int maxLength) { - final int listSize = list.size(); - final List> ret = new ArrayList>(); - if (listSize < maxLength) - ret.add(list); - else - for (int fromIndex = 0, toIndex = maxLength; fromIndex < listSize; fromIndex = toIndex, toIndex += maxLength) - ret.add(list.subList(fromIndex, toIndex > listSize ? listSize : toIndex)); - return ret; - } + // fieldName + listPrefix + 3 parens + ((number expected which is less than maxSize * 2) - 1) assuming 20 items = 39 + 3 = 42 + public static final int defaultInListPreallocLength = Integer.parseInt(System.getProperty("QueryMapper.BindInList.defaultInListPreallocLength", "42")); - private static StringBuilder buildCommaSeparatedList(final Iterable list, final StringBuilder sb) { - boolean notFirst = false; - for (final T obj : list) { - if (notFirst) sb.append(','); - else notFirst = true; - sb.append('?'); - } - return sb; - } - - private static StringBuilder buildInList(final Iterable list, final StringBuilder sb, final String fieldName, final String listPrefix) { - return buildCommaSeparatedList(list, sb.append(fieldName).append(listPrefix)).append(")"); - } - - private static String toInList(final String fieldName, final Collection items, final int maxSize, final String listPrefix, final String listCombine) { - final StringBuilder sb = new StringBuilder("("); - - // do it quick if it will fit in one in-list - if (items.size() < maxSize) // 999 or less - return buildInList(items, sb, fieldName, listPrefix).append(")").toString(); + private static String toNotInListNonEmpty(final String fieldName, final Iterator items, final int maxSize, final String listPrefix, final String listCombine) { + final StringBuilder sb = new StringBuilder(fieldName.length() + listPrefix.length() + defaultInListPreallocLength); + sb.append('('); // else we need to split lists - boolean notFirst = false; - for (final List item : split(items instanceof List ? (List) items : new ArrayList(items), maxSize)) { - if (notFirst) sb.append(listCombine); - else notFirst = true; - buildInList(item, sb, fieldName, listPrefix); + int count; + while(true) { + + sb.append(fieldName).append(listPrefix); + count = 1; + while(true) { + items.next(); + sb.append('?'); + if (!items.hasNext() || ++count > maxSize) + break; + sb.append(','); + } + sb.append(')'); + + if(!items.hasNext()) + break; + sb.append(listCombine); } - return sb.append(")").toString(); + return sb.append(')').toString(); } - private static String toInListNonEmpty(final String fieldName, final Collection items, final int maxSize) { - return toInList(fieldName, items, maxSize, " IN (", " OR "); + private static String toInListNonEmpty(final String fieldName, final Iterator items, final int maxSize) { + return toNotInListNonEmpty(fieldName, items, maxSize, " IN (", " OR "); } - private static String toNotInListNonEmpty(final String fieldName, final Collection items, final int maxSize) { - return toInList(fieldName, items, maxSize, " NOT IN (", " AND "); + private static String toNotInListNonEmpty(final String fieldName, final Iterator items, final int maxSize) { + return toNotInListNonEmpty(fieldName, items, maxSize, " NOT IN (", " AND "); } - public static String toInList(final String fieldName, final Collection items, final int maxSize) { - return items == null || items.isEmpty() ? "(0=1)" : toInListNonEmpty(fieldName, items, maxSize); + public static String toInList(final String fieldName, final Iterator items, final int maxSize) { + return items == null || !items.hasNext() ? inEmpty : toInListNonEmpty(fieldName, items, maxSize); } - public static String toNotInList(final String fieldName, final Collection items, final int maxSize) { - return items == null || items.isEmpty() ? "(1=1)" : toNotInListNonEmpty(fieldName, items, maxSize); + public static String toNotInList(final String fieldName, final Iterator items, final int maxSize) { + return items == null || !items.hasNext() ? notInEmpty : toNotInListNonEmpty(fieldName, items, maxSize); } - public static String toInList(final String fieldName, final Collection items) { + public static String toInList(final String fieldName, final Iterable items, final int maxSize) { + final Iterator itemIt; + return items == null || !(itemIt = items.iterator()).hasNext() ? inEmpty : toInListNonEmpty(fieldName, itemIt, maxSize); + } + + public static String toNotInList(final String fieldName, final Iterable items, final int maxSize) { + final Iterator itemIt; + return items == null || !(itemIt = items.iterator()).hasNext() ? notInEmpty : toNotInListNonEmpty(fieldName, itemIt, maxSize); + } + + public static String toInList(final String fieldName, final T[] items, final int maxSize) { + // is Arrays.asList(items).iterator() the best iterator for Array ? why aren't they Iterable again... + return items == null || items.length == 0 ? inEmpty : toInListNonEmpty(fieldName, Arrays.asList(items).iterator(), maxSize); + } + + public static String toNotInList(final String fieldName, final T[] items, final int maxSize) { + return items == null || items.length == 0 ? notInEmpty : toNotInListNonEmpty(fieldName, Arrays.asList(items).iterator(), maxSize); + } + + public static String toInList(final String fieldName, final Iterator items) { return toInList(fieldName, items, defaultMaxSize); } - public static String toNotInList(final String fieldName, final Collection items) { + public static String toNotInList(final String fieldName, final Iterator items) { + return toNotInList(fieldName, items, defaultMaxSize); + } + + public static String toInList(final String fieldName, final Iterable items) { + return toInList(fieldName, items, defaultMaxSize); + } + + public static String toNotInList(final String fieldName, final Iterable items) { return toNotInList(fieldName, items, defaultMaxSize); } public static String toInList(final String fieldName, final T[] items) { - return toInList(fieldName, Arrays.asList(items), defaultMaxSize); + return toInList(fieldName, items, defaultMaxSize); } public static String toNotInList(final String fieldName, final T[] items) { - return toNotInList(fieldName, Arrays.asList(items), defaultMaxSize); + return toNotInList(fieldName, items, defaultMaxSize); } } diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java index e5027fe..c251434 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java @@ -1,5 +1,7 @@ package com.moparisthebest.jdbc; +import com.moparisthebest.jdbc.util.InListUtil; + import java.sql.Connection; import java.sql.SQLException; import java.util.Collection; @@ -27,8 +29,8 @@ public interface InList { public InListObject notInList(final Connection conn, final String columnName, final Collection values) throws SQLException; class InListObject { - static final InListObject inEmpty = new InListObject("(0=1)"); - static final InListObject notInEmpty = new InListObject("(1=1)"); + static final InListObject inEmpty = new InListObject(InListUtil.inEmpty); + static final InListObject notInEmpty = new InListObject(InListUtil.notInEmpty); private final String sql;