-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbasics.html
executable file
·252 lines (241 loc) · 28 KB
/
basics.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Generated by Apache Maven Doxia Site Renderer 1.3 at May 19, 2012 -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>op4j: bending the Java spoon - The Basics</title>
<style type="text/css" media="all">
@import url("./css/maven-base.css");
@import url("./css/maven-theme.css");
@import url("./css/site.css");
</style>
<link rel="stylesheet" href="./css/print.css" type="text/css" media="print" />
<meta name="Date-Revision-yyyymmdd" content="20120519" />
<meta http-equiv="Content-Language" content="en" />
</head>
<body class="composite">
<div id="banner">
<a href="./" id="bannerLeft">
<img src="images/op4j_logo.png" alt="op4j: bending the Java spoon" />
</a>
<div class="clear">
<hr/>
</div>
</div>
<div id="breadcrumbs">
<div class="xleft">
<span id="publishDate">Last Published: 19 May 2012</span>
| <span id="projectVersion">Version: 1.2</span>
</div>
<div class="xright"> <a href="index.html" title="Main">Main</a>
|
<a href="download.html" title="Download">Download</a>
|
<a href="https://www.bendingthejavaspoon.com" class="externalLink" title="Example Recipes Blog">Example Recipes Blog</a>
|
<a href="https://github.com/op4j/op4j.github.com/issues" class="externalLink" title="Issue Tracking">Issue Tracking</a>
|
<a href="apidocs/index.html" title="Javadoc">Javadoc</a>
|
<a href="https://github.com/op4j" class="externalLink" title="Github Project Page">Github Project Page</a>
</div>
<div class="clear">
<hr/>
</div>
</div>
<div id="leftColumn">
<div id="navcolumn">
<h5>The op4j Project</h5>
<ul>
<li class="none">
<a href="index.html" title="· Main">· Main</a>
</li>
<li class="none">
<a href="download.html" title="· Download">· Download</a>
</li>
<li class="none">
<a href="maveninfo.html" title="· Maven Info">· Maven Info</a>
</li>
<li class="none">
<a href="dependencies.html" title="· Dependencies">· Dependencies</a>
</li>
<li class="none">
<a href="https://github.com/op4j" class="externalLink" title="· Github Repository">· Github Repository</a>
</li>
<li class="none">
<a href="https://www.bendingthejavaspoon.com" class="externalLink" title="· Example Recipes">· Example Recipes</a>
</li>
<li class="none">
<a href="https://github.com/op4j/op4j.github.com/issues" class="externalLink" title="· Issue Tracking">· Issue Tracking</a>
</li>
<li class="expanded">
<a href="#" title="· Documentation">· Documentation</a>
<ul>
<li class="none">
<strong>· The Basics</strong>
</li>
<li class="expanded">
<a href="#" title="· Working with...">· Working with...</a>
<ul>
<li class="none">
<a href="arrays.html" title="· Arrays">· Arrays</a>
</li>
<li class="none">
<a href="lists.html" title="· Lists">· Lists</a>
</li>
<li class="none">
<a href="maps.html" title="· Maps">· Maps</a>
</li>
<li class="none">
<a href="sets.html" title="· Sets">· Sets</a>
</li>
<li class="none">
<a href="generic.html" title="· Any object (generic)">· Any object (generic)</a>
</li>
</ul>
</li>
<li class="expanded">
<a href="#" title="· Functions">· Functions</a>
<ul>
<li class="none">
<a href="functions.html" title="· About Functions">· About Functions</a>
</li>
<li class="none">
<a href="call.html" title="· Call">· Call</a>
</li>
<li class="none">
<a href="get.html" title="· Get">· Get</a>
</li>
<li class="none">
<a href="fnfunc.html" title="· FnFunc">· FnFunc</a>
</li>
<li class="none">
<a href="fnboolean.html" title="· FnBoolean">· FnBoolean</a>
</li>
<li class="none">
<a href="fncalendar.html" title="· FnCalendar">· FnCalendar</a>
</li>
<li class="none">
<a href="fndate.html" title="· FnDate">· FnDate</a>
</li>
<li class="none">
<a href="fnobject.html" title="· FnObject">· FnObject</a>
</li>
<li class="none">
<a href="fnstring.html" title="· FnString">· FnString</a>
</li>
<li class="expanded">
<a href="#" title="· Numbers">· Numbers</a>
<ul>
<li class="none">
<a href="fnnumber.html" title="· FnNumber">· FnNumber</a>
</li>
<li class="none">
<a href="fnbigdecimal.html" title="· FnBigDecimal">· FnBigDecimal</a>
</li>
<li class="none">
<a href="fnbiginteger.html" title="· FnBigInteger">· FnBigInteger</a>
</li>
<li class="none">
<a href="fninteger.html" title="· FnInteger">· FnInteger</a>
</li>
<li class="none">
<a href="fnlong.html" title="· FnLong">· FnLong</a>
</li>
<li class="none">
<a href="fnfloat.html" title="· FnFloat">· FnFloat</a>
</li>
<li class="none">
<a href="fndouble.html" title="· FnDouble">· FnDouble</a>
</li>
<li class="none">
<a href="fndouble.html" title="· FnShort">· FnShort</a>
</li>
</ul>
</li>
<li class="expanded">
<a href="#" title="· Structures">· Structures</a>
<ul>
<li class="none">
<a href="fnarray.html" title="· FnArray">· FnArray</a>
</li>
<li class="none">
<a href="fnlist.html" title="· FnList">· FnList</a>
</li>
<li class="none">
<a href="fnmap.html" title="· FnMap">· FnMap</a>
</li>
<li class="none">
<a href="fnset.html" title="· FnSet">· FnSet</a>
</li>
<li class="none">
<a href="fntuple.html" title="· FnTuple">· FnTuple</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="none">
<a href="apidocs/op4j/index.html" title="· Javadoc">· Javadoc</a>
</li>
<li class="none">
<a href="faq.html" title="· FAQ">· FAQ</a>
</li>
</ul>
</li>
<li class="none">
<a href="license.html" title="· License">· License</a>
</li>
<li class="none">
<a href="team.html" title="· Team">· Team</a>
</li>
</ul>
<ul>
<li class="collapsed">
<a href="ognl-about.html" title="· op4j-ognl">· op4j-ognl</a>
</li>
<li class="collapsed">
<a href="jodatime-about.html" title="· op4j-jodatime">· op4j-jodatime</a>
</li>
</ul>
<a href="https://maven.apache.org" title="Built with Maven 2" class="poweredBy">
<img class="poweredBy" alt="Built with Maven 2" src="https://maven.apache.org/images/logos/maven-feather.png" />
</a>
</div>
</div>
<div id="bodyColumn">
<div id="contentBox">
<div class="section"><h2>Features: a general overview<a name="Features:_a_general_overview"></a></h2><p>Here are some quick details about what op4j can do:</p><ul><li>Apply functions on objects.<ul><li>Including more than 200 predefined functions for data conversion, string handling, calendar operation, math operations, etc...</li></ul></li><li>Manage structures (arrays, lists, maps and sets), including:<ul><li>Easily creating them from their elements (building).</li><li>Modifying them (adding / removing / replacing elements).</li><li>Iterating them, applying functions on each element.</li><li>Transforming them into other structures.</li></ul></li><li>Execute conditional logic (execute actions depending on conditions).</li><li>Define functions from expressions, for later use (similar to closures).</li><li>...and more.</li></ul></div><div class="section"><h2>The key concepts<a name="The_key_concepts"></a></h2><ul><li><a href="#a1">Expressions</a></li><li><a href="#a2">Actions</a></li><li><a href="#a3">Operators</a></li><li><a href="#a4">Targets</a></li><li><a href="#a5">The operators as a state machine</a></li><li><a href="#a6">Functions</a></li><li><a href="#a7">Types</a></li></ul><div class="section"><h3><a name="a1">1</a>. Expressions<a name="a1._Expressions"></a></h3><p>op4j is used for implementing (mainly) auxiliary code as <b>expressions</b>. Expressions look like this:</p><div class="source"><pre>output = Op.on(input).[ACTION].[ACTION]...[ACTION].get();
function = Fn.on(inputType).[ACTION].[ACTION]...[ACTION].get();
</pre></div><p>They start by calling either the <tt>Op.on(...)</tt> or the <tt>Fn.on(...)</tt> static methods, which receive the input object (<i>Op.on</i>) or input type (<i>Fn.on</i>) as a parameter. There are some variations of the "on(...)" methods with slightly different names, which are explained in the documentation sections for the specific types of input.</p><ul><li>Expressions starting with <tt>Op.on</tt> are called <b>Op expressions</b> or <b>Operation expressions</b>. They act on a specific input object/s and perform a set of chained actions on it before returning a result. <div class="source"><pre>String[] values = ...;
List<String> upperStrs = Op.on(values).toList().map(FnString.toUpperCase()).get();
</pre></div></li><li>Expressions starting with <tt>Fn.on</tt> are called <b>Fn expressions</b> or <b>Function expressions</b>. They allow the definition of <i>functions</i> as a set of chained actions of exactly the same kind as <i>op expressions</i>, returning as a result an executable <tt>Function</tt> object equivalent to the defined chain.<div class="source"><pre>Function<String[],List<String>> upperStrsFunc =
Fn.onArrayOf(Types.STRING).map(FnString.toUpperCase()).toList().get();
...
String[] values = ...;
List<String> upperStrs = upperStrsFunc.execute(values);
</pre></div></li></ul><p>Expressions end with <tt>get()</tt>, which returns the output (op expressions) or the defined function (fn expressions).</p></div><div class="section"><h3><a name="a2">2</a>. Actions<a name="a2._Actions"></a></h3><p>An <b>action</b> is a chained method executed in an expression, between the <i>"on(...)"</i> and the <i>"get()"</i> methods.</p><p>For example:</p><div class="source"><pre>String[] values = ...;
List<Integer> intValueList = Op.on(values).toList().forEach().exec(FnString.toInteger()).get();
</pre></div><p>Here we can see three chained actions: <i>toList</i>, <i>forEach</i> and <i>exec</i>. </p></div><div class="section"><h3><a name="a3">3</a>. Operators<a name="a3._Operators"></a></h3><p><b>Operators</b> are the objects representing each of the states of an expression. They are the objects resulting from the execution of <b>actions</b> (or <i>on(...)</i>).</p><ul><li><tt>Op.on(...)</tt> and <tt>Fn.on(...)</tt> return operators.</li><li>Each action method chained after these <i>"on"</i> methods returns a different operator.</li><li><tt>get()</tt> methods stop the action/operator chains and return results.</li></ul><p>Looking again at our example:</p><div class="source"><pre>List<Integer> intValueList = Op.on(values).toList().forEach().exec(FnString.toInteger()).get();
</pre></div><p>We can explain it as:</p><ol style="list-style-type: decimal"><li>The <tt>on(...)</tt> method returns <i>operator1</i>.</li><li>The <tt>toList()</tt> method (or action) is called on <i>operator1</i>, which returns <i>operator2</i>.</li><li>The <tt>forEach()</tt> method (or action) is called on <i>operator2</i>, which returns <i>operator3</i>.</li><li>The <tt>exec(...)</tt> method (or action) is called on <i>operator3</i>, which returns <i>operator4</i>.</li><li>The <tt>get()</tt> method is called on <i>operator4</i>, which returns the expression result.</li></ol><p>All operators are immutable. When an action is executed on them, they return a new and different operator representing the new state, instead of changing their own internal state.</p></div><div class="section"><h3><a name="a4">4</a>. Targets<a name="a4._Targets"></a></h3><p>The "<b>target</b>" or "<b>targets</b>" of an operator are the objects that the operator's actions (methods) will execute on.</p><p>As operators are linked together by actions in the shape of <i>chains</i>, an operator's target is the result of the execution of an action on the previous operator.</p><p>Following the previous example:</p><div class="source"><pre>List<Integer> intValueList = Op.on(values).toList().forEach().exec(FnString.toInteger()).get();
</pre></div><ol style="list-style-type: decimal"><li>The <tt>on(...)</tt> method creates <i>operator1</i>.<ul><li><i>Operator1</i>: TARGET = input (a String[] object called <tt>values</tt>)</li></ul></li><li>The <tt>toList()</tt> method (or action) is called on <i>operator1</i>, which returns <i>operator2</i>.<ul><li><i>Operator2</i>: TARGET = a List<String> object created from the original array.</li></ul></li><li>The <tt>forEach()</tt> method (or action) is called on <i>operator2</i>, which returns <i>operator3</i>.<ul><li><i>Operator3</i>: TARGET = each of the elements of List<String> (an <i>iterating list</i>)</li></ul></li><li>The <tt>exec(...)</tt> method (or action) is called on <i>operator3</i>, which returns <i>operator4</i>.<ul><li><i>Operator4</i>: TARGET (for each execution) = one of the elements of List<String></li></ul></li><li>The <tt>get()</tt> method is called on <i>operator4</i>, which returns the expression result (List<Integer>).</li></ol></div><div class="section"><h3><a name="a5">5</a>. The operators as a state machine<a name="a5._The_operators_as_a_state_machine"></a></h3><p>The behaviour of operators in op4j allows the operator system to be thought of as a <b>state machine</b> where <b>operators represent states</b>, and <b>actions represent state changes</b>. Thanks to this: </p><p><i>Each operator offers only the actions (methods) that can effectively be executed in the specific state it represents</i>.</p><p>What does this mean? It means for example that, if you execute <tt>Op.on(...)</tt> on a <tt>Set<String></tt> object, you will be offered a <tt>forEach()</tt> method for iterating it (because Sets can be iterated), but you will not be offered a <tt>distinct()</tt> method for removing duplicates as would have been offered if your object was a List (because Sets can never contain duplicates).</p><p>Another example, the following sentence will not compile:</p><div class="source"><pre>List<Integer> intValueList = Op.on(values).forEach().forEach()...
</pre></div><p>After the first <tt>forEach()</tt>, you are already iterating the input array, so there is no point in iterating it again!</p><div class="section"><h4>The five branches of the state machine<a name="The_five_branches_of_the_state_machine"></a></h4><p>The operator state machine in op4j defines <b>five branches</b>, this is, five sub-machines with almost entirely different sets of operator classes and thus corresponding associated actions.</p><p>This allows the special treatment of several kinds of objects by offering specific methods for them, as exemplified above. These five branches are:</p><ul><li><b>Array operators</b> for T[] objects.</li><li><b>List operators</b> for List<T> objects.</li><li><b>Map operators</b> for Map<K,V> objects.</li><li><b>Set operators</b> for Set<T> objects.</li><li><b>Generic operators</b> for any other object.</li></ul><p>Operators in each of these five branches will offer different actions depending on the state of the expression (for example, a set operator will offer <tt>forEach()</tt> only if this action has not been added to the chain yet, or it has but an <tt>endFor()</tt> has been called afterwards). </p><p>The <b>array operators branch</b> will be activated if:</p><ul><li><tt>Op.on(input)</tt> is called being <tt>input</tt> an array variable.</li><li><tt>Op.onArrayOf(type, input)</tt> is called being <tt>input</tt> an array variable and <tt>type</tt> the <a class="externalLink" href="https://www.javaruntype.org">javaRuntype</a> <tt>Type</tt> object representing the array's elements (e.g: <tt>Op.onArrayOf(Types.STRING, myStrArr)</tt>).</li><li><tt>Op.onArrayFor(e1, e2, e3...)</tt> is called being <tt>e1</tt>, <tt>e2</tt>, <tt>e3</tt>... the elements on which the expression will be created, treating them as an array. </li><li><tt>Fn.onArrayOf(type)</tt> is called being <tt>type</tt> the type of the elements of the arrays that will be passed as input to the defined function. </li><li>The <tt>asArrayOf(type)</tt> action is called from a <i>generic operator</i>. This action represents a <i>cast</i> operation.</li></ul><p>The <b>list operators branch</b> will be activated if:</p><ul><li><tt>Op.on(input)</tt> is called being <tt>input</tt> a List<i>T</i> variable. </li><li><tt>Op.onList(input)</tt> is called being <tt>input</tt> a List<i>T</i> variable. </li><li><tt>Op.onListFor(e1, e2, e3...)</tt> is called being <tt>e1</tt>, <tt>e2</tt>, <tt>e3</tt>... the elements on which the expression will be created, treating them as a list. </li><li><tt>Fn.onListOf(type)</tt> is called being <tt>type</tt> the type of the elements of the lists that will be passed as input to the defined function. </li><li>The <tt>asListOf(type)</tt> action is called from a <i>generic operator</i>. This action represents a <i>cast</i> operation.</li></ul><p>The <b>map operators branch</b> will be activated if:</p><ul><li><tt>Op.on(input)</tt> is called being <tt>input</tt> a Map<i>K,V</i> variable. </li><li><tt>Op.onMap(input)</tt> is called being <tt>input</tt> a Map<i>K,V</i> variable. </li><li><tt>Op.onMapFor(key, value)</tt> is called being (<tt>key</tt>,<tt>value</tt>) the first entry added to a map on which the expression will be created. Before executing any actions, new entries can be added like <tt>Op.onMapFor(key, value).and(key2, value2).and(key3, value3)...</tt></li><li><tt>Fn.onMapOf(keyType,valueType)</tt> is called being <tt>keyType</tt> and <b>valueType</b> the types of the keys and values of the maps that will be passed as input to the defined function. </li><li>The <tt>asMapOf(keyType,valueType)</tt> action is called from a <i>generic operator</i>. This action represents a <i>cast</i> operation.</li></ul><p>The <b>set operators branch</b> will be activated if:</p><ul><li><tt>Op.on(input)</tt> is called being <tt>input</tt> a Set<i>T</i> variable. </li><li><tt>Op.onSet(input)</tt> is called being <tt>input</tt> a Set<i>T</i> variable. </li><li><tt>Op.onSetFor(e1, e2, e3...)</tt> is called being <tt>e1</tt>, <tt>e2</tt>, <tt>e3</tt>... the elements on which the expression will be created, treating them as a set. </li><li><tt>Fn.onSetOf(type)</tt> is called being <tt>type</tt> the type of the elements of the sets that will be passed as input to the defined function. </li><li>The <tt>asSetOf(type)</tt> action is called from a <i>generic operator</i>. This action represents a <i>cast</i> operation.</li></ul><p>The <b>generic operators branch</b> will be activated if:</p><ul><li><tt>Op.on(input)</tt> is called not being <tt>input</tt> an array, list, map or set.</li><li><tt>Fn.on(type)</tt> is called being <tt>type</tt> the type of the objects that will be passed as input to the defined function. </li><li>The <tt>generic()</tt> action is called from an operator in any of the other four branches.</li></ul></div><div class="section"><h4>Flowing code: the advantage of the state machine <a name="Flowing_code:_the_advantage_of_the_state_machine"></a></h4><p>op4j's state machine makes it easy for you to create your expressions by just using the <i>Content assist</i> feature in your IDE (usually by pressing Ctrl+Space after ".") and going through the list of actions (methods) available to you at a specific point in the chain, selecting the one that fits your needs.</p><img src="images/contentassist.png" alt="Content Assist" /></div></div><div class="section"><h3><a name="a6">6</a>. Functions<a name="a6._Functions"></a></h3><p><b>Functions</b> are a key concept in op4j. A quick definition:</p><p><i>An op4j function is an object of a class which implements the org.op4j.functions.IFunction interface</i></p><p>The IFunction interface is defined as <tt>IFunction<T,R></tt>, being <tt>T</tt> the type of the function input, and <tt>R</tt> the type of the function result. </p><p>IFunction only has one method, <tt>R execute(T input, ExecCtx ctx)</tt>, which receives a T object and a <i>context</i> (an internal structure containing iteration information) and returns an R object.</p><p>All op4j predefined functions, as well as all functions returned by <tt>Fn.on</tt> expressions extend a special implementation of <tt>IFunction<T,R></tt> called <tt>Function<T,R></tt>. This class adds a simpler <tt>R execute(T input)</tt> method, useful for the isolated (not inside an expression) execution of a <tt>Function</tt> object.</p><div class="section"><h4>Executing functions<a name="Executing_functions"></a></h4><p>op4j includes more than 200 functions out-of-the-box, and <b>most actions available in operators correspond to the execution of some of these predefined functions</b>. For example, the <tt>distinct()</tt> action on a set operator created for a <tt>Set<String></tt> input corresponds to the internal execution of the predefined <tt>FnSet.ofString().distinct()</tt> function (which implements <tt>IFunction<Set<String>,Set<String>></tt>).</p><p>Besides, almost every operator offers the <b>exec(IFunction)</b> action, which can take any function as a parameter and execute it on the operator's target. This means that, with <tt>exec(...)</tt>, you can execute:</p><ul><li>Any of the predefined functions.</li><li>Any function you defined by just implementing the <tt>IFunction</tt> interface.</li><li>Any function you defined by executing an <i>fn expression</i>.</li></ul><p>These last kind of functions, the ones defined with <i>fn expressions</i> (which are objects of the special <tt>Function</tt> class), can also be executed by themselves without being part of any other expression:</p><div class="source"><pre>function = Fn.on(...)...get();
output = function.execute(input);
</pre></div></div></div><div class="section"><h3><a name="a7">7</a>. Types<a name="a7._Types"></a></h3><p>op4j is tightly integrated with the <b><a class="externalLink" href="https://www.javaruntype.org">javaRuntype project</a></b>, which in fact was born as a part of op4j (later separated as a project on its own during development). </p><p>javaRuntype offers a runtime type system which fits perfectly the need op4j has for being able to specify types (for example, of a list's elements) including their type parameters (the so-called <i>generics</i>), which is something not covered by the standard <tt>java.lang.Class</tt> objects.</p><p>javaRuntype's <tt>Type</tt> objects are extremely easy to use, and are created and managed by means of the <tt>org.javaruntype.type.Types</tt> class, which in fact contains many useful predefined constants for the most used types.</p></div></div>
</div>
</div>
<div class="clear">
<hr/>
</div>
<div id="footer">
<div class="xright">
Copyright © 2012
<a href="https://www.op4j.org">The OP4J team</a>.
All Rights Reserved.
</div>
<div class="clear">
<hr/>
</div>
</div>
</body>
</html>