/
Enums.shtml
246 lines (199 loc) · 7.8 KB
/
Enums.shtml
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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>
JMRI: Using Enums
</title>
<meta name="author" content="YOUR NAME HERE">
<meta name="keywords" content="SOME KEYWORDS">
<!--#include virtual="/Style.shtml" -->
</head>
<body>
<!--#include virtual="/Header.shtml" -->
<div id="mBody">
<!--#include virtual="Sidebar.shtml" --> <!-- select the local or global Sidebar file -->
<div id="mainContent">
<h1>JMRI: Using Enums</h1>
<h2>The Minimal Enum</h2>
<p>The minimal enum is really small. Here's
an example of embedding an enum in a class to
represent seven different constants:</p>
<pre style="font-family: monospace;">
class MyClass {
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
void checkParty(Day day) {
if (day == Day.FRIDAY) {
doParty();
}
}
}
</pre>
<ul>
<li>This shows a lightweight enum embedded in one class,
but you can also define them independently.
<li>Another class can refer to this as
<code>MyClass.Day</code> and <code>MyClass.Day.FRIDAY</code>
</ul>
<p>
Examples of use:</p>
<pre style="font-family: monospace;">
for (Day day : Day.values()) {
// do what you want
}
</pre>
<pre style="font-family: monospace;">
String whichDay = "THURSDAY";
Day day = Day.valueOf(whichDay);
checkParty(day); // disappointment!
checkParty(Day.TUESDAY); // disappointment!
</pre>
<p>
Note there are no meaningful integer values for this.</p>
<h2>Migrating Integer Constants to Enum</h2>
<p>If you have a set of constants like</p>
<pre style="font-family: monospace;">
static final int DOG = 1;
static final int CAT = 2;
static final int FISH = 3;
static final int BIRD = 12;
</pre>
<p>converting those to an enum can make them more type-safe.</p>
<pre style="font-family: monospace;">
public enum Pet {
DOG(1),
CAT(2),
FISH(3),
BIRD(12);
private final int value;
Pet(int v) { value = v; }
int asInt() { return value; }
}
</pre>
<p>To use this, just replace "int" with "Pet" where-ever one is
defined or passed as a parameter. Then compile and see
what else needs to be changed; if you're not doing arithmetic
with the constants (in which case maybe they're not enums),
there shouldn't be much else that needs to be changed.</p>
<pre style="font-family: monospace;">
void check(int val) {
switch (val) {
case DOG:
// do stuff and return
case CAT:
// do stuff and return
default:
// do stuff and return
}
}
</pre>
<p>becomes</p>
<pre style="font-family: monospace;">
void check(Pet val) {
switch (val) {
case DOG:
// do stuff and return
case CAT:
// do stuff and return
default:
// do stuff and return
}
}
</pre>
<p>(The only change was in the 1st line)</p>
<h2>Adding String Values</h2>
<p>Sometimes you want the elements to also have
user-readable names separate from the
names of the individual items. For example,
you might want to call it TUESDAY in the code,
but have it provide "Tuesday" for pretty printing.</p>
<pre style="font-family: monospace;">
public enum NamedPet {
DOG(1, "Dog"),
CAT(2, "Cat"),
FISH(3, "Fish"),
BIRD(12, "Bird");
private final int value;
private final String name;
Pet(int v, string s) {
value = v;
name = s;
}
int asInt() { return value; }
String toString() { return name; }
}
</pre>
<p>
Note that you might want to internationalize these in the constructor.
See
<a href="https://github.com/JMRI/JMRI/blob/master/java/src/jmri/LocoAddress.java">java/src/jmri/LocoAddress.java</a> for an example of this.
</p>
<p>
In general, you should <u>not</u> build a lot of
code to convert between ints and Enums or between Strings and enums.
That's a code smell that indicates something wrong with how you're
using the enums. If users have to select a specific one, for example, provide a combobox
of values, don't have them type a String that you then have to error-check and
convert. </p>
<p>
The one exception to this is the ConvertXML persistance system,
which wants to convert your enum values to and from String values
to store and load in XML files, and may also need to convert from the numeric values for
historical reasons. See below.</p>
<h2>ConvertXML</h2>
<p>
Enums can provide interfaces. We use the
<code>StringConvertibleEnum</code> and
<code>IntConvertibleEnum</code>
interfaces as flags.
<h4>Migration</h4>
Start writing a new schema that only allows the specific elements,
but make sure your code can take the old numeric values.
Since the file contains the schema it obeys, this is OK.
But it might require a lot of migrations if you do this
between test releases....
<h4>Schema limiting to a set of specific enum values</h4>
<pre style="font-family: monospace;">
<xs:attribute name="connection" default="unspecified" >
<xs:simpleType>
<xs:restriction base="xs:token" >
<xs:enumeration value="unspecified"/>
<xs:enumeration value="plug"/>
<xs:enumeration value="wire"/>
<xs:enumeration value="solder"/>
<xs:enumeration value="LED"/>
<xs:enumeration value="bulb"/>
<xs:enumeration value="other"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</pre>
<h4>Schema also permitting older numeric values</h4>
<pre style="font-family: monospace;">
<xs:attribute name="size">
<xs:simpleType>
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:positive-integer">
<xs:maxInclusive="10"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="small"/>
<xs:enumeration value="medium"/>
<xs:enumeration value="large"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:attribute>
</pre>
This can also be used for elements (which is the generally prefered approach)
<!--#include virtual="/Footer.shtml" -->
</div><!-- closes #mainContent-->
</div> <!-- closes #mBody, was opened by Sidebar -->
</body>
</html>