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);
}
}