From 1c8bc7132d980c1ff2dbd6b9af579c3b2fd8c63e Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 3 Apr 2016 19:22:48 -0400 Subject: General code refactoring and maintenance --- .../java/bjc/utils/funcdata/FunctionalList.java | 123 ++++++++++++++--- .../java/bjc/utils/funcdata/FunctionalMap.java | 151 +++++++++++++++++++++ .../utils/funcdata/FunctionalStringTokenizer.java | 47 ++++++- .../bjc/utils/funcdata/bst/BinarySearchTree.java | 11 ++ .../utils/funcdata/bst/BinarySearchTreeLeaf.java | 12 ++ .../utils/funcdata/bst/BinarySearchTreeNode.java | 27 ++++ 6 files changed, 347 insertions(+), 24 deletions(-) create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java (limited to 'BJC-Utils2/src/main/java/bjc/utils/funcdata') diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java index a260d78..ff02515 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java @@ -1,10 +1,10 @@ package bjc.utils.funcdata; -import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.Random; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -16,6 +16,8 @@ import bjc.utils.data.GenHolder; import bjc.utils.data.IHolder; import bjc.utils.data.Pair; +import java.util.ArrayList; + /** * A wrapper over another list that provides eager functional operations * over it. Differs from a stream in every way except for the fact that @@ -62,6 +64,10 @@ public class FunctionalList implements Cloneable { * The source for a backing list */ public FunctionalList(FunctionalList sourceList) { + if (sourceList == null) { + throw new NullPointerException("Source list must be non-null"); + } + // Find out if this should make a copy of the source's wrapped list // instead. // @@ -88,6 +94,11 @@ public class FunctionalList implements Cloneable { * The list to use as a backing list. */ public FunctionalList(List backingList) { + if (backingList == null) { + throw new NullPointerException( + "Backing list must be non-null"); + } + wrappedList = backingList; } @@ -112,6 +123,10 @@ public class FunctionalList implements Cloneable { * predicate. */ public boolean allMatch(Predicate matchPredicate) { + if (matchPredicate == null) { + throw new NullPointerException("Predicate must be non-null"); + } + for (E item : wrappedList) { if (!matchPredicate.test(item)) { // We've found a non-matching item @@ -132,6 +147,10 @@ public class FunctionalList implements Cloneable { * predicate. */ public boolean anyMatch(Predicate matchPredicate) { + if (matchPredicate == null) { + throw new NullPointerException("Predicate must be not null"); + } + for (E item : wrappedList) { if (matchPredicate.test(item)) { // We've found a matching item @@ -176,13 +195,20 @@ public class FunctionalList implements Cloneable { public FunctionalList combineWith( FunctionalList rightList, BiFunction itemCombiner) { + if (rightList == null) { + throw new NullPointerException( + "Target combine list must not be null"); + } else if (itemCombiner == null) { + throw new NullPointerException("Combiner must not be null"); + } + FunctionalList returnedList = new FunctionalList<>(); // Get the iterator for the other list Iterator rightIterator = rightList.toIterable().iterator(); - for (Iterator leftIterator = wrappedList - .iterator(); leftIterator.hasNext() + for (Iterator leftIterator = + wrappedList.iterator(); leftIterator.hasNext() && rightIterator.hasNext();) { // Add the transformed items to the result list E leftVal = leftIterator.next(); @@ -212,6 +238,11 @@ public class FunctionalList implements Cloneable { * @return The first element in this list. */ public E first() { + if (wrappedList.size() < 1) { + throw new NoSuchElementException( + "Attempted to get first element of empty list"); + } + return wrappedList.get(0); } @@ -227,14 +258,23 @@ public class FunctionalList implements Cloneable { * @return A new list containing the flattened results of applying the * provided function. */ - public FunctionalList flatMap( - Function> elementExpander) { - FunctionalList returnedList = new FunctionalList<>( - this.wrappedList.size()); + public FunctionalList + flatMap(Function> elementExpander) { + if (elementExpander == null) { + throw new NullPointerException("Expander must not be null"); + } + + FunctionalList returnedList = + new FunctionalList<>(this.wrappedList.size()); forEach(element -> { - FunctionalList expandedElement = elementExpander - .apply(element); + FunctionalList expandedElement = + elementExpander.apply(element); + + if (expandedElement == null) { + throw new NullPointerException( + "Expander returned null list"); + } // Add each element to the returned list expandedElement.forEach(returnedList::add); @@ -250,6 +290,10 @@ public class FunctionalList implements Cloneable { * The action to apply to each member of the list. */ public void forEach(Consumer action) { + if (action == null) { + throw new NullPointerException("Action is null"); + } + wrappedList.forEach(action); } @@ -261,6 +305,10 @@ public class FunctionalList implements Cloneable { * index. */ public void forEachIndexed(BiConsumer indexedAction) { + if (indexedAction == null) { + throw new NullPointerException("Action must not be null"); + } + // This is held b/c ref'd variables must be final/effectively final GenHolder currentIndex = new GenHolder<>(0); @@ -302,6 +350,10 @@ public class FunctionalList implements Cloneable { * @return A list containing all elements that match the predicate */ public FunctionalList getMatching(Predicate matchPredicate) { + if (matchPredicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + FunctionalList returnedList = new FunctionalList<>(); wrappedList.forEach((element) -> { @@ -344,8 +396,12 @@ public class FunctionalList implements Cloneable { * @return A new list containing the mapped elements of this list. */ public FunctionalList map(Function elementTransformer) { - FunctionalList returnedList = new FunctionalList<>( - this.wrappedList.size()); + if (elementTransformer == null) { + throw new NullPointerException("Transformer must be not null"); + } + + FunctionalList returnedList = + new FunctionalList<>(this.wrappedList.size()); forEach(element -> { // Add the transformed item to the result @@ -366,8 +422,8 @@ public class FunctionalList implements Cloneable { * @return A list containing pairs of this element and the specified * list */ - public FunctionalList> pairWith( - FunctionalList rightList) { + public FunctionalList> + pairWith(FunctionalList rightList) { return combineWith(rightList, Pair::new); } @@ -378,13 +434,21 @@ public class FunctionalList implements Cloneable { * The size of elements to put into each one of the sublists * @return A list partitioned into partitions of size nPerPart */ - public FunctionalList> partition( - int numberPerPartition) { - FunctionalList> returnedList = new FunctionalList<>(); + public FunctionalList> + partition(int numberPerPartition) { + if (numberPerPartition < 1 + || numberPerPartition > wrappedList.size()) { + throw new IllegalArgumentException("" + numberPerPartition + + " is an invalid partition size. Must be between 1 and " + + wrappedList.size()); + } + + FunctionalList> returnedList = + new FunctionalList<>(); // The current partition being filled - GenHolder> currentPartition = new GenHolder<>( - new FunctionalList<>()); + GenHolder> currentPartition = + new GenHolder<>(new FunctionalList<>()); this.forEach((element) -> { if (isPartitionFull(numberPerPartition, currentPartition)) { @@ -433,6 +497,11 @@ public class FunctionalList implements Cloneable { * @return A random element from this list. */ public E randItem(Random rnd) { + if (rnd == null) { + throw new NullPointerException( + "Random source must not be null"); + } + int randomIndex = rnd.nextInt(wrappedList.size()); return wrappedList.get(randomIndex); @@ -460,6 +529,12 @@ public class FunctionalList implements Cloneable { public F reduceAux(T initialValue, BiFunction stateAccumulator, Function resultTransformer) { + if (stateAccumulator == null) { + throw new NullPointerException("Accumulator must not be null"); + } else if (resultTransformer == null) { + throw new NullPointerException("Transformer must not be null"); + } + // The current collapsed list IHolder currentState = new GenHolder<>(initialValue); @@ -481,6 +556,10 @@ public class FunctionalList implements Cloneable { * @return Whether there was anything that satisfied the predicate */ public boolean removeIf(Predicate removePredicate) { + if (removePredicate == null) { + throw new NullPointerException("Predicate must be non-null"); + } + return wrappedList.removeIf(removePredicate); } @@ -502,7 +581,8 @@ public class FunctionalList implements Cloneable { * @param searchKey * The key to search for. * @param comparator - * The way to compare elements for searching + * The way to compare elements for searching. Pass null to + * use the natural ordering for E * @return The element if it is in this list, or null if it is not. */ public E search(E searchKey, Comparator comparator) { @@ -524,7 +604,8 @@ public class FunctionalList implements Cloneable { * elements. Does change the underlying list. * * @param comparator - * The way to compare elements for sorting. + * The way to compare elements for sorting. Pass null to use + * E's natural ordering */ public void sort(Comparator comparator) { Collections.sort(wrappedList, comparator); @@ -554,7 +635,7 @@ public class FunctionalList implements Cloneable { // Remove trailing space and comma sb.deleteCharAt(sb.length() - 1); - //sb.deleteCharAt(sb.length() - 2); + // sb.deleteCharAt(sb.length() - 2); sb.append(")"); diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java new file mode 100644 index 0000000..0eb2e94 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java @@ -0,0 +1,151 @@ +package bjc.utils.funcdata; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import bjc.utils.data.Pair; + +/** + * Functional wrapper over map providing some useful things + * + * @author ben + * + * @param + * The type of this map's keys + * @param + * The type of this map's values + * + */ +public class FunctionalMap { + private final class TransformedMap extends FunctionalMap { + private FunctionalMap mapToTransform; + private Function transformer; + + public TransformedMap(FunctionalMap destMap, + Function transform) { + mapToTransform = destMap; + transformer = transform; + } + + @Override + public V2 get(K key) { + return transformer.apply(mapToTransform.get(key)); + } + } + + private Map wrappedMap; + + /** + * Create a new blank functional map + */ + public FunctionalMap() { + wrappedMap = new HashMap<>(); + } + + /** + * Create a new functional map wrapping the specified map + * + * @param wrap + * The map to wrap + */ + public FunctionalMap(Map wrap) { + if (wrap == null) { + throw new NullPointerException("Map to wrap must not be null"); + } + + wrappedMap = wrap; + } + + /** + * Create a new functional map with the specified entries + * + * @param entries + * The entries to put into the map + */ + @SafeVarargs + public FunctionalMap(Pair... entries) { + this(); + + for (Pair entry : entries) { + entry.doWith((key, val) -> { + wrappedMap.put(key, val); + }); + } + } + + /** + * Add an entry to the map + * + * @param key + * The key to put the value under + * @param val + * The value to add + * @return The previous value of the key in the map, or null if the key + * wasn't in the map. However, note that it may also return + * null if the key was set to null. + * + */ + public V put(K key, V val) { + if (key == null) { + throw new NullPointerException("Key must not be null"); + } + + return wrappedMap.put(key, val); + } + + /** + * Get the value assigned to the given key + * + * @param key + * The key to look for a value under + * @return The value of the key + * + * + */ + public V get(K key) { + if (key == null) { + throw new NullPointerException("Key must not be null"); + } + + if (wrappedMap.containsKey(wrappedMap)) { + return wrappedMap.get(key); + } else { + throw new IllegalArgumentException( + "Key " + key + " is not present in the map"); + } + } + + /** + * Transform the values returned by this map. + * + * NOTE: This transform is applied once for each lookup of a value, so + * the transform passed should be a proper function, or things will + * likely not work as expected. + * + * @param + * The new type of returned values + * @param transformer + * The function to use to transform values + * @return The map where each value will be transformed after lookup + */ + public FunctionalMap + mapValues(Function transformer) { + if (transformer == null) { + throw new NullPointerException("Transformer must not be null"); + } + + return new TransformedMap<>(this, transformer); + } + + /** + * Check if this map contains the specified key + * + * @param key + * The key to check + * @return Whether or not the map contains the key + */ + public boolean containsKey(K key) { + return wrappedMap.containsKey(key); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java index 3c819cd..386b732 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java @@ -19,6 +19,11 @@ public class FunctionalStringTokenizer { * @return A new tokenizer that splits the provided string on spaces. */ public static FunctionalStringTokenizer fromString(String strang) { + if (strang == null) { + throw new NullPointerException( + "String to tokenize must be non-null"); + } + return new FunctionalStringTokenizer( new StringTokenizer(strang, " ")); } @@ -35,6 +40,11 @@ public class FunctionalStringTokenizer { * The string to tokenize */ public FunctionalStringTokenizer(String inp) { + if (inp == null) { + throw new NullPointerException( + "String to tokenize must be non-null"); + } + this.input = new StringTokenizer(inp); } @@ -49,6 +59,14 @@ public class FunctionalStringTokenizer { */ public FunctionalStringTokenizer(String inputString, String seperators) { + if (inputString == null) { + throw new NullPointerException( + "String to tokenize must not be null"); + } else if (seperators == null) { + throw new NullPointerException( + "Tokens to split on must not be null"); + } + this.input = new StringTokenizer(inputString, seperators); } @@ -59,6 +77,11 @@ public class FunctionalStringTokenizer { * The non-functional string tokenizer to wrap */ public FunctionalStringTokenizer(StringTokenizer toWrap) { + if (toWrap == null) { + throw new NullPointerException( + "Wrapped tokenizer must not be null"); + } + this.input = toWrap; } @@ -69,6 +92,10 @@ public class FunctionalStringTokenizer { * The action to execute for each token */ public void forEachToken(Consumer action) { + if (action == null) { + throw new NullPointerException("Action must not be null"); + } + while (input.hasMoreTokens()) { action.accept(input.nextToken()); } @@ -84,7 +111,7 @@ public class FunctionalStringTokenizer { } /** - * Return the next token from the tokenizer Returns null if no more + * Return the next token from the tokenizer. Returns null if no more * tokens are available * * @return The next token from the tokenizer @@ -110,19 +137,33 @@ public class FunctionalStringTokenizer { * The function to use to convert tokens. * @return A list containing all of the converted tokens. */ - public FunctionalList toList(Function tokenTransformer) { + public FunctionalList + toList(Function tokenTransformer) { + if (tokenTransformer == null) { + throw new NullPointerException("Transformer must not be null"); + } + FunctionalList returnList = new FunctionalList<>(); // Add each token to the list after transforming it forEachToken(token -> { E transformedToken = tokenTransformer.apply(token); - + returnList.add(transformedToken); }); return returnList; } + /** + * Convert this tokenizer into a list of strings + * + * @return This tokenizer, converted into a list of strings + */ + public FunctionalList toList() { + return toList((String element) -> element); + } + /** * Check if this tokenizer has more tokens * diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java index ec0e4df..fa92f85 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java @@ -39,6 +39,10 @@ public class BinarySearchTree { * The thing to use for comparing elements */ public BinarySearchTree(Comparator cmp) { + if (cmp == null) { + throw new NullPointerException("Comparator must not be null"); + } + elementCount = 0; comparator = cmp; } @@ -169,6 +173,13 @@ public class BinarySearchTree { */ public void traverse(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { + if (linearizationMethod == null) { + throw new NullPointerException( + "Linearization method must not be null"); + } else if (traversalPredicate == null) { + throw new NullPointerException("Predicate must not be nulls"); + } + rootElement.forEach(linearizationMethod, traversalPredicate); } diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java index 7e31328..d2f9013 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java @@ -55,6 +55,10 @@ public class BinarySearchTreeLeaf implements ITreePart { @Override public E collapse(Function leafTransformer, BiFunction branchCollapser) { + if (leafTransformer == null) { + throw new NullPointerException("Transformer must not be null"); + } + return leafTransformer.apply(data); } @@ -101,6 +105,10 @@ public class BinarySearchTreeLeaf implements ITreePart { */ @Override public boolean directedWalk(DirectedWalkFunction treeWalker) { + if (treeWalker == null) { + throw new NullPointerException("Tree walker must not be null"); + } + switch (treeWalker.walk(data)) { case SUCCESS: return true; @@ -119,6 +127,10 @@ public class BinarySearchTreeLeaf implements ITreePart { @Override public boolean forEach(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { + if (traversalPredicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return traversalPredicate.test(data); } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java index 77bb196..09a4912 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java @@ -51,6 +51,10 @@ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { */ @Override public void add(T element, Comparator comparator) { + if (comparator == null) { + throw new NullPointerException("Comparator must not be null"); + } + switch (comparator.compare(data, element)) { case -1: if (leftBranch == null) { @@ -79,6 +83,10 @@ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { @Override public E collapse(Function nodeCollapser, BiFunction branchCollapser) { + if (nodeCollapser == null || branchCollapser == null) { + throw new NullPointerException("Collapser must not be null"); + } + E collapsedNode = nodeCollapser.apply(data); if (leftBranch != null) { @@ -112,6 +120,10 @@ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { @Override public boolean contains(T element, Comparator comparator) { + if (comparator == null) { + throw new NullPointerException("Comparator must not be null"); + } + return directedWalk(currentElement -> { switch (comparator.compare(element, currentElement)) { case -1: @@ -128,6 +140,10 @@ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { @Override public void delete(T element, Comparator comparator) { + if (comparator == null) { + throw new NullPointerException("Comparator must not be null"); + } + directedWalk(currentElement -> { switch (comparator.compare(data, element)) { case -1: @@ -145,6 +161,10 @@ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { @Override public boolean directedWalk(DirectedWalkFunction treeWalker) { + if (treeWalker == null) { + throw new NullPointerException("Walker must not be null"); + } + switch (treeWalker.walk(data)) { case SUCCESS: return true; @@ -162,6 +182,13 @@ public class BinarySearchTreeNode extends BinarySearchTreeLeaf { @Override public boolean forEach(TreeLinearizationMethod linearizationMethod, Predicate traversalPredicate) { + if (linearizationMethod == null) { + throw new NullPointerException( + "Linearization method must not be null"); + } else if (traversalPredicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + switch (linearizationMethod) { case PREORDER: return preorderTraverse(linearizationMethod, -- cgit v1.2.3