Skip to main content

Implement Custom Google Guava Splitter Class

Problem : Create a thread safe class Spliiter that divides strings into substrings, by recognizing a separator which can be expressed as a single character, literal string, regular expression or by using a fixed substring length. Basic Usage Example: Splitter.on(',').split("foo,,bar, quux") will return ["foo", "", "bar", " quux"].

You can also add configuration for trimming result or omit empty strings. For example: Splitter.on(',').trimResults().omitEmptyStrings().split("foo, ,bar, quux,") returns ["foo", "bar", "quux"].

The below code works but I would like to know if there are any multi-threading issue or possibility of further optimizing the code.

Thanks in advance.

Solution:

package com.corejavaspace.testpackage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

/**
 * The Class Splitter.
 */
public final class Splitter {
/** The omit empty. */
private boolean omitEmpty;

/** The trim. */
private boolean trim;

/** The limit. */
private int limit;

/** The split type. */
private SplitType splitType;

/**
 * The Interface SplitType.
 */
public interface SplitType {
    Iterable<String> iterator(Splitter splitter, CharSequence toSplit);
}

/**
 * Instantiates a new splitter.
 *
 * @param split type
 * @param omit empty
 * @param trim
 * @param limit
 */
private Splitter(SplitType splitType, boolean omitEmpty, boolean trim, int limit) {
    this.splitType = splitType;
    this.omitEmpty = omitEmpty;
    this.trim = trim;
    this.limit = limit;
}

/**
 * Adds configuration on which splitting will be performed
 *
 * @param separator
 * @return splitter
 */
public static Splitter on(char separator) {
    return new Splitter(new SplitType() {

        @Override
        public Iterable<String> iterator(Splitter splitter, CharSequence toSplit) {

            final int len = toSplit.length();

            List<String> result = new ArrayList<String>();
            int i = 0, start = 0;

            while (i < len) {
                if (toSplit.charAt(i) == separator) {
                    result.add(((String) toSplit).substring(start, i));
                    start = ++i;
                    continue;
                }

                i++;
            }

            result.add(((String) toSplit).substring(start, i));
            result = handleTrimConfig(result, splitter.trim, splitter.omitEmpty);
            return result;
        }
    }, false, false, Integer.MAX_VALUE);
}

/**
 * Adds configuration on which splitting will be performed
 *
 * @param separator
 * @return splitter
 */
public static Splitter on(final String separator) {
    return new Splitter(new SplitType() {

        @Override
        public Iterable<String> iterator(Splitter splitter, CharSequence toSplit) {

            String[] result = ((String) toSplit).split(separator);

            return handleTrimConfig(Arrays.asList(result), splitter.trim, splitter.omitEmpty);

        }
    }, false, false, Integer.MAX_VALUE);
}

/**
 * Performs trim and omit empty operations based on configuration.
 *
 * @param input list
 * @param trim flag
 * @param omit empty flag
 * @return return list
 */
private static List<String> handleTrimConfig(List<String> list, boolean trim, boolean omitEmpty) {
    List<String> copyList = new ArrayList<String>(list);
    Iterator<String> iterator = copyList.iterator();
    int index = 0;
    while (iterator.hasNext()) {
        String element = iterator.next();
        if (trim && omitEmpty) {
            element = element.trim();
            if (element.equals("")) {
                iterator.remove();
                index--;
            } else {
                copyList.set(index, element);
            }

        } else if (trim) {
            element = element.trim();
            copyList.set(index, element);
        } else if (omitEmpty) {
            if (element.equals("")) {
                iterator.remove();
            }
        }
        index++;
    }

    return copyList;
}

/**
 * Split input into fixed length parts.
 *
 * @param length the length
 * @return the splitter
 */
public static Splitter splitFixedLength(int length) {
    if (length <= 0) {
        throw new IllegalArgumentException("Input to splitFixedLenth is not valid");
    }
    return new Splitter(new SplitType() {

        @Override
        public Iterable<String> iterator(Splitter splitter, CharSequence toSplit) {

            List<String> split = new ArrayList<>();
            for (int i = 0; i <= toSplit.length() / length; i++) {
                split.add(((String) toSplit).substring(i * length, Math.min((i + 1) * length, toSplit.length())));
            }
            split = handleTrimConfig(split, splitter.trim, splitter.omitEmpty);
            return split;
        }
    }, false, false, length);
}

/**
 * Adds configuration on which splitting will be performed
 *
 * @param separator pattern
 * @return splitter
 */
public static Splitter on(Pattern separatorPattern) {
    return new Splitter(new SplitType() {

        @Override
        public Iterable<String> iterator(Splitter splitter, CharSequence toSplit) {
            String[] result = separatorPattern.split(toSplit);
            return handleTrimConfig(Arrays.asList(result), splitter.trim, splitter.omitEmpty);

        }
    }, false, false, Integer.MAX_VALUE);
}

/**
 * Whether to omit empty strings or not.
 *
 * @return splitter
 */
public Splitter omitEmptyStrings() {
    this.omitEmpty = true;
    return this;

}

/**
 * Whether to trim strings or not.
 *
 * @return splitter
 */
public Splitter trimResults() {

    this.trim = true;
    return this;
}

/**
 * Performs splitting based on set configuration.
 *
 * @param  sequence
 * @return Iterable<String>
 */
public Iterable<String> split(CharSequence sequence) {
    if (sequence == null) {
        throw new IllegalArgumentException("Input to split is not valid");
    }
    return splitType.iterator(Splitter.this, sequence);

}

}
Atul
  • 41
  • 1