Functionals - Toolbox
Functionals? Well. Almost.
Current topic is the AppCollections
(and its friends) and package eu.qualityontime.functionals
.
AppCollections
It is a utility function collection of some collection related fuctions. It can be called helper class.
- simple wrapper around existing helper methods (mostly related to functional helpers)
- factory methods of certain collection implementations:
Map()
,IMap()
etc. - functional helpers:
sort
,find
, etc. - non existing helpers or null-save helpers: e.g.:
isEmpty
Factory methods
Example: Map()
, IMap()
, List()
, IList()
One of the most boring programming task is to write and read something like new ArrayList<Some>()
. It is full of noise:
- Implementation details even if I am using the same implementation everywhere (e.g.: in 90% of case
ArrayList
is the best implementation - there are statistics that array list is performing the best in mixed, average usage) - generics noise (remember Java 6 has no empty diamond)
-
new
keyword as noise. - standard collections do not have initializer constructor (e.g when you want to fill a
Map
with some predefined values) and still want to make them mutable (so noArrays.asList
).
Alternatives: Guava have similar factory methods in Maps
, Lists
, etc classes. But I do prefer List
over newArrayList()
and IList(...)
over ImmutableList.of(...)
.
The advantages of using simple factory method is trivial once you are composing them:
vs.
Non-existing helpers
Simplest example: isEmpty
Implementation:
There is no trick. There is no any special code behind. It is simply as it is: null save helpers which does not exists in standard JDK.
Alternatives: Commons Collections has similar functionality. But it is possible that you do not want to have certain dependencies when you plan to use a few helper method only.
On the other hand dependencies like Commons Collections , Commons Lang , Guava are never “real” dependencies. They are just extensions on the weak JDK java.util
package.
Functional helpers
Once you get used to Functional Programming paradigm you will change your style of code. For more info you must read Guava Explained . Similar implementation is available in Commons Collections too.
But why do I need wrapper?
First of all you do not need it. You should develop a small wrapper around collections and using it. See later in description of package eu.qualityontime.functionals
.
If you are not developing any wrapper you still have some advantages over using “plain” libraries. (even if I have reasoned against in the previous section).
-
Façade to simplify accessing 3rd party libraries. I do not want to remember which specific class to call when transforming values:
Iterables
?Lists
?,Maps
? (from Guava ). - It is always a good idea to hide 3rd party libaries behind a Bridge. Originally I was using Commons Collections for (eg) transforming lists. At that time Commons Collections was not supporting generics. So a second version of the library was using generics as much as possible. Then I have moved to some other derivative of Commons Collections which supports generics (example). And finally I have changed to Guava . The change was always transparent to old code because I was supporting both kind of functional API through the
AppCollections
. Lickily libraries are interface compatibles so writing some wrapper around aTranformer
of Commons Collections to imitateFunction
of Guava .
Functional package
Package eu.qualityontime.functionals
:
FIterable
FMap
FMultimap
F
prefix means functional. All these classes are wrapper around the appropriate type and delgate all method call. And as an addition it is extending them by few useful functional stuff.
What does the following code do?
1 List<Todo> todos = ... 2 Predicate<Todo> completed = ... 3 Function<Todo, List<User>> assignedUsers = ... 4 Function<User, Long> nationality_id = ... 5 Function<User, Map<String, Object>> to_map = ... 6 Function<Long, String> to_string = ... 7 ... 8 //and the magic 9 Map<String, Collection<Map<String,Object>> = FIterable(todos) //FIterable<Todo> 10 .filter(completed) //FIterable<Todo> 11 .flatMap(assignedUsers) //FIterable<User> 12 .groupBy(nationality_id) //FMultimap<Long, User> 13 .transformValues(to_map) //FMultimal<Long, Map<String, Object>> 14 .asMap() //FMap<Long, Collection<Map<String,Object>> 15 .mapKeys(to_string);//FMap<String, Collection<Map<String,Object>>
Do you really have any difficulties to understand (even without comments)? Simply beautifull!
I will never again develop it
- Soha a büdös életben nem fogom újra lefejleszteni
- Functionals - Toolbox