A generic operator is what you will get when creating an expression (Op.on(...) or Fn.on(...)) on any object which is not an array, a list, a map or a set. This is, an operator which will let you execute actions on your objects, but not offer any special built-in features like iterating with forEach().
Generic operation expressions are created on an object which is neither an array, nor a list, map or set:
Op.on(object)...
Also, any operator on arrays, lists, maps or sets can be turned into a generic operator by executing the generic() action:
Op.onList(...).generic().[GENERIC ACTIONS]...
Generic operators, as all others, return their results by means of the get() action:
newObject = Op.on(object)...get();
Generic operators can convert their targets into singleton arrays, lists, sets or maps. This means creating one of these structures and then adding only one element (the target) to them.
For creating a singleton array:
String[] array = Op.on(str).intoSingletonArrayOf(Types.STRING).get();
Maps are a little bit trickier, because each element of a map (a map entry) is in fact composed of two objects instead of one: a key, and a value.
That is why, in order to obtain a map with a single entry from the generic operator's target, we will have to either apply a map builder function, or simply add (zip) another object as key or value.
A Map Builder is an function which returns map entries (IFunction<T,Map.Entry<K,V>>), usually created by extending the abstract class org.op4j.functions.MapBuilder, and which provides op4j with a way of creating a map entry from each of the list's elements.
MapBuilder looks like this:
public abstract class MapBuilder<T,K,V> implements IFunction<T,Map.Entry<K,V>> { public abstract K buildKey(final T target); public abstract V buildValue(final T target); ... }
Let's use it for creating our singleton map:
MapBuilder<String,Integer,Calendar> mapBuilder = ...; Map<Integer,Calendar> map = Op.on(str).intoSingletonMap(mapBuilder).get();
The singleton map can also be created by zipping. This means either considering the generic operator's target object as a key and then adding (zipping) a value, or the opposite.
Let's add the value:
// map = {{1="a"}} Map<Integer,String> map = Op.on(1).zipValue("a").get();
Or the contrary:
// map = {{"a"=1}} Map<String,Integer> map = Op.on(1).zipKey("a").get();
Alternatively, a function can be used for evaluating the target object and obtaining the zipped key or value:
IFunction<Integer,String> valueEvaluatorFn = ...; Map<Integer,String> map = Op.on(1).zipValueBy(valueEvaluatorFn).get();
IFunction<Integer,String> keyEvaluatorFn = ...; Map<String,Integer> map = Op.on(1).zipKeyBy(keyEvaluatorFn).get();
In generic operators, functions are executed the usual way:
String upperStr = Op.on("a String").exec(FnString.toUpperCase()).get();
A condition can be added for null-saving a function execution, if needed:
String upperStr = Op.on(str).execIfNotNull(FnString.toUpperCase()).get();
op4j allows the conditional execution of actions. Once the condition (an action starting with "if") is executed, all subsequent actions will apply only on the target object only if it has been selected (condition was true).
For example, lets convert into upper case only if the String value is not "uncapitalizable".
String upper = Op.on(str).ifTrue(FnString.notEq("uncapitalizable")).exec(FnString.toUpperCase()).get();
As usual, selections can be ended with endIf(...):
Op.on(...).ifTrue(...).[ACTIONS ON SELECTED ELEMENTS].endIf()...
Selection can be based on the nullity of the target:
Op.on(...).ifNull().... Op.on(...).ifNotNull()....
And also on the value returned by the evaluation of a function returning Boolean:
IFunction<T,Boolean> eval = ...; ... Op.on(...).ifTrue(eval)... Op.on(...).ifFalse(eval)...
After executing a selection action, function executed by means of an exec action cannot change the operator type.
So this would not be valid:
// Will not compile! Integer intObj = Op.on(str).ifTrue(FnString.notEq("-")).exec(FnString.toInteger()).get();
...because converting the operator target only sometimes (if some condition is true) means that the real type of the target object cannot be known after executing.
Operator targets can be replaced by other objects:
String newString = Op.on(str).ifNull().replaceWith("[no value]").get();
...which is equivalent to:
String newString = Op.on(str).replaceIfNotNullWith("[no value]").get();