package org.codefx.libfx.collection.transform;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
/**
* Demonstrates how to use the {@link OptionalTransformingSet}.
* <p>
* The demonstrated example is based on the situation that some code produces a {@link Set} of {@link Optional} strings.
* Since this is generally undesired, the {@code OptionalTransformingSet} is used to extract the strings.
*/
public class OptionalTransformingSetDemo {
// #begin FIELDS
/**
* The inner set, which - for some strange reason - contains {@link Optional}s.
*/
private final Set<Optional<String>> innerSet;
/**
* The transformation without {@link Optional}.
*/
private final Set<String> transformingSet;
// #end FIELDS
// #begin CONSTRUCTION & MAIN
/**
* Creates a new demo.
*/
public OptionalTransformingSetDemo() {
innerSet = new HashSet<>();
transformingSet = new OptionalTransformingSet<String>(innerSet, String.class, null);
}
/**
* Runs this demo.
*
* @param args
* command line arguments (will not be used)
*/
public static void main(String[] args) {
print("Outputs are written as 'Modification -> innerSet.toString ~ transformingSet.toString'".toUpperCase());
print();
OptionalTransformingSetDemo demo = new OptionalTransformingSetDemo();
demo.modifyingInnerSet();
demo.modifyingTransformedSet();
demo.exceptionOnInnerNullElements();
demo.breakingInverseFunctions();
}
// #end CONSTRUCTION & MAIN
// #begin DEMOS
private void modifyingInnerSet() {
print("-- Modifying the inner set --");
print("Insert optionals for 'A', 'B', 'C'");
innerSet.add(Optional.of("A"));
innerSet.add(Optional.of("B"));
innerSet.add(Optional.of("C"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Remove optional for 'B'");
innerSet.remove(Optional.of("B"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Insert empty optional");
innerSet.add(Optional.empty());
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Insert optionals for 'Ax', 'Cx', 'Cy'");
innerSet.add(Optional.of("Ax"));
innerSet.add(Optional.of("Cx"));
innerSet.add(Optional.of("Cy"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Remove optionals with content starting with 'C'");
innerSet.removeIf(optional -> optional.map(string -> string.startsWith("C")).orElse(false));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Clear");
innerSet.clear();
print("\t -> " + innerSet + " ~ " + transformingSet);
print();
}
private void modifyingTransformedSet() {
print("-- Modifying the transforming set --");
print("Insert 'A', 'B', 'C'");
transformingSet.add(("A"));
transformingSet.add(("B"));
transformingSet.add(("C"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Remove 'B'");
transformingSet.remove(("B"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Insert default value for empty optional (which is null)");
transformingSet.add(null);
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Insert 'Ax', 'Cx', 'Cy'");
transformingSet.add(("Ax"));
transformingSet.add(("Cx"));
transformingSet.add(("Cy"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Remove strings starting with 'C'");
transformingSet.removeIf(string -> string != null && string.startsWith("C"));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Clear");
transformingSet.clear();
print("\t -> " + innerSet + " ~ " + transformingSet);
print();
}
private void exceptionOnInnerNullElements() {
print("-- Causing a NullPointerException when accessing an inner map with null --");
print("The 'OptionalTransformingMap' does not allow the inner map to contain null"
+ " ('Optional.empty()' should be used instead).");
print("Inserting null into inner set will cause no exception");
innerSet.add(null);
print("But viewing a set with null will:");
try {
print("\t -> " + innerSet + " ~ " + transformingSet);
} catch (NullPointerException ex) {
print("\t " + ex.toString());
}
print("Clear");
innerSet.clear();
print("\t -> " + innerSet + " ~ " + transformingSet);
print();
}
private void breakingInverseFunctions() {
print("-- Breaking the contract with non-inverse functions --");
print("If a default value is specified which occurs in one of the optionals,"
+ " the implicitly created transformations are non-inverse.");
print("This can be used to create unexpected behavior...");
print();
print("Creating a map with default value 'DEFAULT'.");
String defaultValue = "DEFAULT";
Set<String> transformingSet = new OptionalTransformingSet<String>(innerSet, String.class, defaultValue);
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Insert empy optional into inner set");
innerSet.add(Optional.empty());
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Insert optional with default string into inner set");
innerSet.add(Optional.of(defaultValue));
print("\t -> " + innerSet + " ~ " + transformingSet);
print("Sizes of different sets");
print("\t inner set: " + innerSet.size());
print("\t transforming set: " + transformingSet.size());
print("\t new set: " + new HashSet<>(transformingSet).size() + " (!)");
print("Now try to remove the value from the transforming set:");
print("\t before: " + transformingSet);
print("\t remove 'DEFAULT' (returns " + transformingSet.remove(defaultValue) + ") -> " + transformingSet);
print("\t remove 'DEFAULT' (returns " + transformingSet.remove(defaultValue) + ") -> " + transformingSet);
print("\t Damn it!");
print("The transforming set does not contain its own elements:");
print("\t 'transformingSet.contains(transformingSet.iterator().next())' -> "
+ transformingSet.contains(transformingSet.iterator().next()));
print("Clear");
innerSet.clear();
print("\t -> " + innerSet + " ~ " + transformingSet);
print();
}
// #end DEMOS
private static void print() {
System.out.println();
}
private static void print(String text) {
System.out.println(text);
}
}