Changeset 7bb516f for doc/theses/jiada_liang_MMath/relatedwork.tex
- Timestamp:
- Feb 22, 2024, 11:44:38 AM (3 months ago)
- Branches:
- master
- Children:
- 2810700, 624ba3a5
- Parents:
- 38f5006
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/jiada_liang_MMath/relatedwork.tex
r38f5006 r7bb516f 2 2 \label{s:RelatedWork} 3 3 4 Enumerations exist in many popular programming languages, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}, and the algebraic data-type in functional programming.5 There are a large set of overlapping features among these languages, but each language has its own unique extensions and restrictions.4 An enumeration type exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}, and the algebraic data-type in functional programming. 5 Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions. 6 6 7 7 … … 48 48 escapechar=\$, % LaTeX escape in code 49 49 moredelim=**[is][\color{red}]{@}{@}, % red highlighting @...@ 50 literate={'}{\ttfamily'\!}1 % remove '-' literate as comment 50 51 }% lstset 51 52 \lstset{#1}% necessary 52 53 }{} 53 54 54 An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators) of the type.55 An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators). 55 56 \begin{ada} 56 57 type RGB is ( @Red@, @Green@, Blue ); -- 3 literals (enumerators) … … 58 59 No other enumerators are assignable to objects of this type. 59 60 Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1. 61 To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization. 62 \begin{ada} 63 type RGB is ( Red, Green, Blue ); 64 @for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order 65 \end{ada} 66 60 67 Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope. 61 Note, Ada is case- insensitiveso names may appear in multiple forms and still be the same name (a questionable design decision).62 The only operators on enumeration types are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators.68 Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same name (a questionable design decision). 69 The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators, which is always ascending. 63 70 64 71 Ada enumerators are overloadable. … … 67 74 \end{ada} 68 75 Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names. 69 Figure~\VRef{f:AdaEnumeration} shows how ambiguities are handled using a cast, \eg @RGB'(Red)@.76 Figure~\VRef{f:AdaEnumeration} shows how ambiguities are handled using a cast, \eg \lstinline[language=ada]{RGB'(Red)}. 70 77 71 78 \begin{figure} … … 73 80 with Ada.Text_IO; use Ada.Text_IO; 74 81 procedure test is 75 type RGB is ( Red, Green, Blue );76 type Traffic_Light is ( Red, Yellow, Green );77 procedure @ Print@( Colour : RGB ) is begin82 type RGB is ( @Red@, Green, Blue ); 83 type Traffic_Light is ( @Red@, Yellow, Green ); 84 procedure @Red@( Colour : RGB ) is begin 78 85 Put_Line( "Colour is " & RGB'Image( Colour ) ); 79 end Print;80 procedure @ Print@( TL : Traffic_Light ) is begin86 end Red; 87 procedure @Red@( TL : Traffic_Light ) is begin 81 88 Put_Line( "Light is " & Traffic_Light'Image( TL ) ); 82 end Print;89 end Red; 83 90 begin 84 Print( Blue ); $\C[2in]{-- RGB}$85 Print( Yellow ); $\C{-- Traffic\_Light}$86 Print( @RGB'(Red)@ ); $\C{-- ambiguous without cast}\CRT$91 @Red@( Blue ); -- RGB 92 @Red@( Yellow ); -- Traffic_Light 93 @Red@( @RGB'(Red)@ ); -- ambiguous without cast 87 94 end test; 88 95 \end{ada} … … 91 98 \end{figure} 92 99 93 Like many other declarative items, enumeration literals can be renamed. 94 In fact, such a literal is actually a function, so it has to be renamed as such: 95 \begin{ada} 96 function Red return P.RGB renames P.Red; 97 \end{ada} 98 Here, @RGB@ is assumed to be defined in package @P@, which is visible at the place of the renaming declaration. 99 Renaming makes @Red@ directly visible without necessity to resort the use-clause. 100 Ada provides an alias mechanism called \lstinline[language=ada]{renames} for aliasing types, especially to shorten package type names. 101 \begin{ada} 102 OtherRed : RGB renames Red; 103 \end{ada} 104 which suggests the \CFA extension to @typedef@. 105 \begin{cfa} 106 typedef RGB.Red OtherRed; 107 \end{cfa} 100 108 101 109 There are four enumeration pseudo functions (attributes): @'Pos@, @'Val@, @'Image@, and @'Value@. … … 105 113 RGB'Val(0) = Red 106 114 \end{ada} 107 Funcion @Image@ returns enumerator label (in capital letters); the inverse function @Value@ returns the corresponding enumerator.115 Funcion @Image@ returns the enumerator label (in capital letters); the inverse function @Value@ returns the corresponding enumerator. 108 116 \begin{ada} 109 117 RGB'Image( Red ) = "RED" … … 111 119 \end{ada} 112 120 These attributes are important for simple IO (there are more elaborate IO facilities in @Ada.Text_IO@ for enumeration types). 113 As well, an enumeration type, @T@, has the additional attributes, @T'First@, @T'Last@, @T'Range@, @T'Pred@, @T'Succ@, @T'Min@, and @T'Max@, producing an intuitively result based on the attribute name. 114 115 116 Note that redeclaration as a function does not affect the staticness of the literal. 117 118 \paragraph{Characters as enumeration literals} ~\newline 121 As well, an enumeration type @T@ has the additional attributes, @T'First@, @T'Last@, @T'Range@, @T'Pred@, @T'Succ@, @T'Min@, and @T'Max@, producing an intuitive result based on the attribute name. 122 123 Ada leverages enumerations as the bases for character and boolean types. 119 124 Rather unique to Ada is the use of character literals as enumeration literals: 120 125 \begin{ada} … … 156 161 Hence, the ordering of the enumerators is crucial to provide the necessary ranges. 157 162 158 \paragraph{Using enumerations} ~\newline 159 Enumeration types being scalar subtypes, type attributes such as @First@ and @Succ@ will allow stepping through a subsequence of the values. 163 \begin{ada} 164 type Subtype_Name is (Id1, Id2, Id3 ... ); 165 \end{ada} 166 where @Id1@, @Id2@, etc. are identifiers or characters literals. 167 In either case, the legal values of the type are referred to as "enumeration literals." 168 Each of these values has a "position number" corresponding to its position in the list such that @Id1@ has position 0, @Id2@ has position 1, and the Nth value has position N-1. 169 170 The enumeration attributes @First@ and @Succ@ allow stepping through a subsequence of the values. 160 171 \begin{ada} 161 172 case Day_Of_Week'First is … … 183 194 \end{ada} 184 195 185 \begin{ada}186 type Subtype_Name is (Id1, Id2, Id3 ... );187 \end{ada}188 where @Id1@, @Id2@, etc. are identifiers or characters literals.189 In either case, the legal values of the type are referred to as "enumeration literals."190 Each of these values has a "position number" corresponding to its position in the list such that @Id1@ has position 0, @Id2@ has position 1, and the Nth value has position N-1.191 192 193 \section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE194 195 \lstnewenvironment{csharp}[1][]{% necessary196 \lstset{197 language=[Sharp]C,198 escapechar=\$, % LaTeX escape in code199 moredelim=**[is][\color{red}]{@}{@}, % red highlighting @...@200 }% lstset201 \lstset{#1}% necessary202 }{}203 204 An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type.205 To define an enumeration type, use the enum keyword and specify the names of enum members:206 \begin{csharp}207 enum Season {208 Spring,209 Summer,210 Autumn,211 Winter212 }213 \end{csharp}214 By default, the associated constant values of enum members are of type @int@;215 they start with zero and increase by one following the definition text order.216 217 You can explicitly specify any other integral numeric type as an underlying type of an enumeration type.218 You can also explicitly specify the associated constant values, as the following example shows:219 \begin{csharp}220 enum ErrorCode : ushort {221 None = 0,222 Unknown = 1,223 ConnectionLost = 100,224 OutlierReading = 200225 }226 \end{csharp}227 You cannot define a method inside the definition of an enumeration type.228 To add functionality to an enumeration type, create an extension method.229 230 The default value of an enumeration type @E@ is the value produced by expression @(E)0@, even if zero doesn't have the corresponding enum member.231 232 You use an enumeration type to represent a choice from a set of mutually exclusive values or a combination of choices.233 To represent a combination of choices, define an enumeration type as bit flags.234 235 \paragraph{Enumeration types as bit flags}236 237 If you want an enumeration type to represent a combination of choices, define enum members for those choices such that an individual choice is a bit field.238 That is, the associated values of those enum members should be the powers of two.239 Then, you can use the bitwise logical operators @|@ or @&@ to combine choices or intersect combinations of choices, respectively.240 To indicate that an enumeration type declares bit fields, apply the @Flags@ attribute to it.241 As the following example shows, you can also include some typical combinations in the definition of an enumeration type.242 \begin{csharp}243 [Flags]244 public enum Days {245 None = 0b_0000_0000, // 0246 Monday = 0b_0000_0001, // 1247 Tuesday = 0b_0000_0010, // 2248 Wednesday = 0b_0000_0100, // 4249 Thursday = 0b_0000_1000, // 8250 Friday = 0b_0001_0000, // 16251 Saturday = 0b_0010_0000, // 32252 Sunday = 0b_0100_0000, // 64253 Weekend = Saturday | Sunday254 }255 256 public class FlagsEnumExample {257 public static void Main() {258 Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;259 Console.WriteLine(meetingDays);260 // Output:261 // Monday, Wednesday, Friday262 263 Days workingFromHomeDays = Days.Thursday | Days.Friday;264 Console.WriteLine($\$$"Join a meeting by phone on {meetingDays & workingFromHomeDays}");265 // Output:266 // Join a meeting by phone on Friday267 268 bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;269 Console.WriteLine($\$$"Is there a meeting on Tuesday: {isMeetingOnTuesday}");270 // Output:271 // Is there a meeting on Tuesday: False272 273 var a = (Days)37;274 Console.WriteLine(a);275 // Output:276 // Monday, Wednesday, Saturday277 }278 }279 \end{csharp}280 For more information and examples, see the System.FlagsAttribute API reference page and the Non-exclusive members and the Flags attribute section of the System.Enum API reference page.281 282 \paragraph{The System.Enum type and enum constraint}283 284 The System.Enum type is the abstract base class of all enumeration types.285 It provides a number of methods to get information about an enumeration type and its values.286 For more information and examples, see the System.Enum API reference page.287 288 You can use System.Enum in a base class constraint (that is known as the enum constraint) to specify that a type parameter is an enumeration type.289 Any enumeration type also satisfies the struct constraint, which is used to specify that a type parameter is a non-nullable value type.290 Conversions291 292 For any enumeration type, there exist explicit conversions between the enumeration type and its underlying integral type.293 If you cast an enum value to its underlying type, the result is the associated integral value of an enum member.294 \begin{csharp}295 public enum Season296 {297 Spring,298 Summer,299 Autumn,300 Winter301 }302 303 public class EnumConversionExample304 {305 public static void Main()306 {307 Season a = Season.Autumn;308 Console.WriteLine($\$$"Integral value of {a} is {(int)a}"); // output: Integral value of Autumn is 2309 310 var b = (Season)1;311 Console.WriteLine(b); // output: Summer312 313 var c = (Season)4;314 Console.WriteLine(c); // output: 4315 }316 }317 \end{csharp}318 319 196 320 197 \section{\CC} … … 330 207 }{} 331 208 332 \CC is backwards compatible with C, so it inherited C's enumerations.209 \CC is largely backwards compatible with C, so it inherited C's enumerations. 333 210 However, the following non-backwards compatible changes have been made. 334 211 … … 398 275 399 276 277 \section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE 278 279 \lstnewenvironment{csharp}[1][]{% necessary 280 \lstset{ 281 language=[Sharp]C, 282 escapechar=\$, % LaTeX escape in code 283 moredelim=**[is][\color{red}]{@}{@}, % red highlighting @...@ 284 }% lstset 285 \lstset{#1}% necessary 286 }{} 287 288 % https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx 289 290 \Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to C/\CC enumeration. 291 \begin{csharp} 292 enum Weekday : byte { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday@,@ }; 293 \end{csharp} 294 The default underlying type is @int@, with auto-incrementing, implicit/explicit intialization, terminator comma, and optional integral typing (default @int@) 295 A method cannot be defined in an enumeration type. 296 As well, there is an explicit bidirectional conversion between an enumeration and its integral type, and an implicit conversion to the enumerator label in display contexts. 297 \begin{csharp} 298 int day = (int)Weekday.Friday; $\C{// day == 10}$ 299 Weekday weekday = (Weekdays)42; $\C{// weekday == 42}$ 300 Console.WriteLine( Weekday.Friday ); $\C{// print Friday}$ 301 string mon = Weekday.Monday.ToString(); 302 \end{csharp} 303 304 The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable. 305 \begin{csharp} 306 foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) { 307 Console.WriteLine( constant + " " + (int)constant ); // label, position 308 } 309 \end{csharp} 310 311 The @Flags@ attribute creates a bit-flags enumeration, allowing bitwise operators @&@, @|@, @~@ (complement), @^@ (xor). 312 \begin{csharp} 313 @[Flags]@ public enum Weekday { 314 None = 0x0, Monday = 0x1, Tuesday = 0x2, Wednesday = 0x4, 315 Thursday = 0x8, Friday = 0x10, Saturday = 0x20, Sunday = 0x40, 316 Weekend = @Saturday | Sunday@, 317 Weekdays = @Monday | Tuesday | Wednesday | Thursday | Friday@ 318 } 319 Weekday meetings = @Weekday.Monday | Weekday.Wednesday@; // 0x5 320 \end{csharp} 321 322 \Csharp supports an enumeration class to embed enumeration operations, where the enumerators are objects. 323 \begin{csharp} 324 public class PaymentType : Enumeration { 325 public static readonly PaymentType DebitCard = new PaymentType(0); 326 public static readonly PaymentType CreditCard = new PaymentType(1); 327 private PaymentType(int value, [CallerMemberName] string name = null) : base(value, name) { } 328 } 329 \end{csharp} 330 Find a meaningful example and test it. 331 332 400 333 \section{Golang} 401 334 … … 409 342 }{} 410 343 411 The Golang enumeration is similar to classical Pascal \lstinline[language=pascal]{const}, where the type of a \lstinline[language=Golang]{const} name is the type of its constant. 344 The Golang enumeration is similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression. 345 \begin{Go} 346 const ( R = 0; G; B ) $\C{// implicit: 0 0 0}$ 347 const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$ 348 const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$ 349 \end{Go} 412 350 Constant names are unscoped and must be unique (no overloading). 413 351 The first enumerator \emph{must} be explicitly initialized; 414 352 subsequent enumerators can be implicitly or explicitly initialized. 415 Implicit initialization is the previous (left) enumerator value. 416 \begin{Go} 417 const ( R = 0; G; B ) $\C{// implicit: 0 0 0}$ 418 const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$ 419 const ( H = 0; Jack = "Jack"; J, K = 3; I ) $\C{// type change, implicit/explicit: 0 Jack Jack 3 3}$ 420 \end{Go} 353 Implicit initialization is the previous (predecessor) enumerator value. 421 354 422 355 Auto-incrementing is supported by the keyword \lstinline[language=Go]{iota}, available only in the \lstinline[language=Go]{const} declaration. 423 The \lstinline[language=Go]{iota} is a \emph{per \lstinline[language=golang]{const} declaration} integer counter, starting at zero and implicitly incremented by one for each \lstinline[language=golang]{const} identifier .356 The \lstinline[language=Go]{iota} is a \emph{per \lstinline[language=golang]{const} declaration} integer counter, starting at zero and implicitly incremented by one for each \lstinline[language=golang]{const} identifier (enumerator). 424 357 \begin{Go} 425 358 const ( R = @iota@; G; B ) $\C{// implicit: 0 1 2}$ … … 441 374 @Thursday = 10;@ Friday = @iota - Wednesday + Thursday - 1@; Saturday; Sunday ) // 10, 11, 12, 13 442 375 \end{Go} 443 Note, \lstinline[language=Go]{iota} is advanced for the explicitly initialized enumerator, like the underscore @_@ identifier. 376 Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier. 377 444 378 445 379 \section{Java} 380 381 \lstnewenvironment{Java}[1][]{% necessary 382 \lstset{ 383 language=Java, 384 escapechar=\$, % LaTeX escape in code 385 moredelim=**[is][\color{red}]{`}{`}, % red highlighting @...@ 386 }% lstset 387 \lstset{#1}% necessary 388 }{} 389 390 Here's a quick and simple example of an enum that defines the status of a pizza order; the order status can be ORDERED, READY or DELIVERED: 391 \begin{Java} 392 public enum PizzaStatus { 393 ORDERED, 394 READY, 395 DELIVERED; 396 } 397 \end{Java} 398 Additionally, enums come with many useful methods that we would otherwise need to write if we were using traditional public static final constants. 399 400 \paragraph{Custom Enum Methods} 401 402 Now that we have a basic understanding of what enums are and how we can use them, we'll take our previous example to the next level by defining some extra API methods on the enum: 403 \begin{Java} 404 public class Pizza { 405 private PizzaStatus status; 406 public enum PizzaStatus { 407 ORDERED, 408 READY, 409 DELIVERED; 410 } 411 public boolean isDeliverable() { 412 if (getStatus() == PizzaStatus.READY) { 413 return true; 414 } 415 return false; 416 } 417 // Methods that set and get the status variable. 418 } 419 \end{Java} 420 421 \paragraph{Comparing Enum Types Using "==" Operator} 422 423 Since enum types ensure that only one instance of the constants exist in the JVM, we can safely use the "==" operator to compare two variables, like we did in the above example. 424 Furthermore, the "==" operator provides compile-time and run-time safety. 425 426 First, we'll look at run-time safety in the following snippet, where we'll use the "==" operator to compare statuses. 427 Either value can be null and we won't get a NullPointerException. Conversely, if we use the equals method, we will get a NullPointerException: 428 \begin{Java} 429 if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED)); 430 if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED); 431 \end{Java} 432 As for compile-time safety, let's look at an example where we'll determine that an enum of a different type is equal by comparing it using the equals method. 433 This is because the values of the enum and the getStatus method coincidentally are the same; 434 however, logically the comparison should be false. We avoid this issue by using the "==" operator. 435 436 The compiler will flag the comparison as an incompatibility error: 437 \begin{Java} 438 if(testPz.getStatus().equals(TestColor.GREEN)); 439 if(testPz.getStatus() == TestColor.GREEN); 440 \end{Java} 441 442 \paragraph{Using Enum Types in Switch Statements} 443 444 We can use enum types in switch statements also: 445 \begin{Java} 446 public int getDeliveryTimeInDays() { 447 switch (status) { 448 case ORDERED: return 5; 449 case READY: return 2; 450 case DELIVERED: return 0; 451 } 452 return 0; 453 } 454 \end{Java} 455 456 \paragraph{Fields, Methods and Constructors in Enums} 457 458 We can define constructors, methods, and fields inside enum types, which makes them very powerful. 459 460 Next, let's extend the example above by implementing the transition from one stage of a pizza order to another. 461 We'll see how we can get rid of the if and switch statements used before: 462 \begin{Java} 463 public class Pizza { 464 private PizzaStatus status; 465 public enum PizzaStatus { 466 ORDERED (5){ 467 @Override 468 public boolean isOrdered() { 469 return true; 470 } 471 }, 472 READY (2){ 473 @Override 474 public boolean isReady() { 475 return true; 476 } 477 }, 478 DELIVERED (0){ 479 @Override 480 public boolean isDelivered() { 481 return true; 482 } 483 }; 484 485 private int timeToDelivery; 486 public boolean isOrdered() {return false;} 487 public boolean isReady() {return false;} 488 public boolean isDelivered(){return false;} 489 public int getTimeToDelivery() { 490 return timeToDelivery; 491 } 492 PizzaStatus (int timeToDelivery) { 493 this.timeToDelivery = timeToDelivery; 494 } 495 } 496 public boolean isDeliverable() { 497 return this.status.isReady(); 498 } 499 public void printTimeToDeliver() { 500 System.out.println("Time to delivery is " + 501 this.getStatus().getTimeToDelivery()); 502 } 503 // Methods that set and get the status variable. 504 } 505 \end{Java} 506 The test snippet below demonstrates how this works: 507 \begin{Java} 508 @Test 509 public void givenPizaOrder_whenReady_thenDeliverable() { 510 Pizza testPz = new Pizza(); 511 testPz.setStatus(Pizza.PizzaStatus.READY); 512 assertTrue(testPz.isDeliverable()); 513 } 514 \end{Java} 515 516 \paragraph{EnumSet and EnumMap} 517 518 \paragraph{EnumSet} 519 520 The EnumSet is a specialized Set implementation that's meant to be used with Enum types. 521 522 Compared to a HashSet, it's a very efficient and compact representation of a particular Set of Enum constants, owing to the internal Bit Vector Representation that's used. 523 It also provides a type-safe alternative to traditional int-based "bit flags," allowing us to write concise code that's more readable and maintainable. 524 525 The EnumSet is an abstract class that has two implementations, RegularEnumSet and JumboEnumSet, one of which is chosen depending on the number of constants in the enum at the time of instantiation. 526 527 Therefore, it's a good idea to use this set whenever we want to work with a collection of enum constants in most scenarios (like subsetting, adding, removing, and bulk operations like containsAll and removeAll), and use Enum.values() if we just want to iterate over all possible constants. 528 529 In the code snippet below, we can see how to use EnumSet to create a subset of constants: 530 \begin{Java} 531 public class Pizza { 532 private static EnumSet<PizzaStatus> undeliveredPizzaStatuses = 533 EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY); 534 private PizzaStatus status; 535 public enum PizzaStatus { 536 ... 537 } 538 public boolean isDeliverable() { 539 return this.status.isReady(); 540 } 541 public void printTimeToDeliver() { 542 System.out.println("Time to delivery is " + 543 this.getStatus().getTimeToDelivery() + " days"); 544 } 545 public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) { 546 return input.stream().filter( 547 (s) -> undeliveredPizzaStatuses.contains(s.getStatus())) 548 .collect(Collectors.toList()); 549 } 550 public void deliver() { 551 if (isDeliverable()) { 552 PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy() 553 .deliver(this); 554 this.setStatus(PizzaStatus.DELIVERED); 555 } 556 } 557 // Methods that set and get the status variable. 558 } 559 \end{Java} 560 561 Executing the following test demonstrates the power of the EnumSet implementation of the Set interface: 562 \begin{Java} 563 @Test 564 public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() { 565 List<Pizza> pzList = new ArrayList<>(); 566 Pizza pz1 = new Pizza(); 567 pz1.setStatus(Pizza.PizzaStatus.DELIVERED); 568 569 Pizza pz2 = new Pizza(); 570 pz2.setStatus(Pizza.PizzaStatus.ORDERED); 571 572 Pizza pz3 = new Pizza(); 573 pz3.setStatus(Pizza.PizzaStatus.ORDERED); 574 575 Pizza pz4 = new Pizza(); 576 pz4.setStatus(Pizza.PizzaStatus.READY); 577 578 pzList.add(pz1); 579 pzList.add(pz2); 580 pzList.add(pz3); 581 pzList.add(pz4); 582 583 List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList); 584 assertTrue(undeliveredPzs.size() == 3); 585 } 586 \end{Java} 587 588 \paragraph{EnumMap} 589 590 EnumMap is a specialized Map implementation meant to be used with enum constants as keys. 591 Compared to its counterpart HashMap, it's an efficient and compact implementation that's internally represented as an array: 592 \begin{Java} 593 EnumMap<Pizza.PizzaStatus, Pizza> map; 594 \end{Java} 595 Let's look at an example of how we can use it in practice: 596 \begin{Java} 597 public static EnumMap<PizzaStatus, List<Pizza>> 598 groupPizzaByStatus(List<Pizza> pizzaList) { 599 EnumMap<PizzaStatus, List<Pizza>> pzByStatus = 600 new EnumMap<PizzaStatus, List<Pizza>>(PizzaStatus.class); 601 602 for (Pizza pz : pizzaList) { 603 PizzaStatus status = pz.getStatus(); 604 if (pzByStatus.containsKey(status)) { 605 pzByStatus.get(status).add(pz); 606 } else { 607 List<Pizza> newPzList = new ArrayList<Pizza>(); 608 newPzList.add(pz); 609 pzByStatus.put(status, newPzList); 610 } 611 } 612 return pzByStatus; 613 } 614 \end{Java} 615 Executing the following test demonstrates the power of the EnumMap implementation of the Map interface: 616 \begin{Java} 617 @Test 618 public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() { 619 List<Pizza> pzList = new ArrayList<>(); 620 Pizza pz1 = new Pizza(); 621 pz1.setStatus(Pizza.PizzaStatus.DELIVERED); 622 623 Pizza pz2 = new Pizza(); 624 pz2.setStatus(Pizza.PizzaStatus.ORDERED); 625 626 Pizza pz3 = new Pizza(); 627 pz3.setStatus(Pizza.PizzaStatus.ORDERED); 628 629 Pizza pz4 = new Pizza(); 630 pz4.setStatus(Pizza.PizzaStatus.READY); 631 632 pzList.add(pz1); 633 pzList.add(pz2); 634 pzList.add(pz3); 635 pzList.add(pz4); 636 637 EnumMap<Pizza.PizzaStatus,List<Pizza>> map = Pizza.groupPizzaByStatus(pzList); 638 assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1); 639 assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2); 640 assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1); 641 } 642 \end{Java} 643 644 \paragraph{Singleton Pattern} 645 646 Normally, implementing a class using the Singleton pattern is quite non-trivial. 647 Enums provide a quick and easy way of implementing singletons. 648 649 In addition, since the enum class implements the Serializable interface under the hood, the class is guaranteed to be a singleton by the JVM. 650 This is unlike the conventional implementation, where we have to ensure that no new instances are created during deserialization. 651 652 In the code snippet below, we see how we can implement a singleton pattern: 653 \begin{Java} 654 public enum PizzaDeliverySystemConfiguration { 655 INSTANCE; 656 PizzaDeliverySystemConfiguration() { 657 // Initialization configuration which involves 658 // overriding defaults like delivery strategy 659 } 660 661 private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL; 662 663 public static PizzaDeliverySystemConfiguration getInstance() { 664 return INSTANCE; 665 } 666 667 public PizzaDeliveryStrategy getDeliveryStrategy() { 668 return deliveryStrategy; 669 } 670 } 671 \end{Java} 672 673 \paragraph{Strategy Pattern} 674 675 Conventionally, the Strategy pattern is written by having an interface that is implemented by different classes. 676 677 Adding a new strategy means adding a new implementation class. 678 With enums, we can achieve this with less effort, and adding a new implementation means simply defining another instance with some implementation. 679 680 The code snippet below shows how to implement the Strategy pattern: 681 \begin{Java} 682 public enum PizzaDeliveryStrategy { 683 EXPRESS { 684 @Override 685 public void deliver(Pizza pz) { 686 System.out.println("Pizza will be delivered in express mode"); 687 } 688 }, 689 NORMAL { 690 @Override 691 public void deliver(Pizza pz) { 692 System.out.println("Pizza will be delivered in normal mode"); 693 } 694 }; 695 696 public abstract void deliver(Pizza pz); 697 } 698 \end{Java} 699 Then we add the following method to the Pizza class: 700 \begin{Java} 701 public void deliver() { 702 if (isDeliverable()) { 703 PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy() 704 .deliver(this); 705 this.setStatus(PizzaStatus.DELIVERED); 706 } 707 } 708 709 @Test 710 public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() { 711 Pizza pz = new Pizza(); 712 pz.setStatus(Pizza.PizzaStatus.READY); 713 pz.deliver(); 714 assertTrue(pz.getStatus() == Pizza.PizzaStatus.DELIVERED); 715 } 716 \end{Java} 717 718 8. Java 8 and Enums 719 720 We can rewrite the Pizza class in Java 8, and see how the methods getAllUndeliveredPizzas() and groupPizzaByStatus() become so concise with the use of lambdas and the Stream APIs: 721 \begin{Java} 722 public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) { 723 return input.stream().filter( 724 (s) -> !deliveredPizzaStatuses.contains(s.getStatus())) 725 .collect(Collectors.toList()); 726 } 727 728 public static EnumMap<PizzaStatus, List<Pizza>> 729 groupPizzaByStatus(List<Pizza> pzList) { 730 EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().collect( 731 Collectors.groupingBy(Pizza::getStatus, 732 () -> new EnumMap<>(PizzaStatus.class), Collectors.toList())); 733 return map; 734 } 735 \end{Java} 736 446 737 447 738 \section{Modula-3}
Note: See TracChangeset
for help on using the changeset viewer.