Skip to content

Commit 30a2f04

Browse files
YassinHajajsjmillington
authored andcommitted
BAEL-3533 - Scala Pattern Matching (Switch/Case) (eugenp#8226)
* BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case) * BAEL-3533 Scala Pattern Matching (Switch/Case)
1 parent 94a65a5 commit 30a2f04

File tree

2 files changed

+345
-0
lines changed

2 files changed

+345
-0
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package com.baeldung.scala
2+
3+
// Case Class
4+
abstract class Animal
5+
6+
case class Mammal(name: String, fromSea: Boolean) extends Animal
7+
8+
case class Bird(name: String) extends Animal
9+
10+
case class Fish(name: String) extends Animal
11+
12+
// Sealed Class
13+
sealed abstract class CardSuit
14+
15+
case class Spike() extends CardSuit
16+
17+
case class Diamond() extends CardSuit
18+
19+
case class Heart() extends CardSuit
20+
21+
case class Club() extends CardSuit
22+
23+
object Person {
24+
def apply(fullName: String) = fullName
25+
26+
def unapply(fullName: String): Option[String] = {
27+
if (!fullName.isEmpty)
28+
Some(fullName.replaceAll("(?<=\\w)(\\w+)", "."))
29+
else
30+
None
31+
}
32+
}
33+
34+
class PatternMatching {
35+
36+
def caseClassesPatternMatching(animal: Animal): String = {
37+
animal match {
38+
case Mammal(name, fromSea) => s"I'm a $name, a kind of mammal. Am I from the sea? $fromSea"
39+
case Bird(name) => s"I'm a $name, a kind of bird"
40+
case _ => "I'm an unknown animal"
41+
}
42+
}
43+
44+
def constantsPatternMatching(constant: Any): String = {
45+
constant match {
46+
case 0 => "I'm equal to zero"
47+
case 4.5d => "I'm a double"
48+
case false => "I'm the contrary of true"
49+
case _ => s"I'm unknown and equal to $constant"
50+
}
51+
}
52+
53+
def sequencesPatternMatching(sequence: Any): String = {
54+
sequence match {
55+
case List(singleElement) => s"I'm a list with one element: $singleElement"
56+
case List(_, _*) => s"I'm a list with one or multiple elements: $sequence"
57+
case Vector(1, 2, _*) => s"I'm a vector: $sequence"
58+
case _ => s"I'm an unrecognized sequence. My value: $sequence"
59+
}
60+
}
61+
62+
def tuplesPatternMatching(tuple: Any): String = {
63+
tuple match {
64+
case (first, second) => s"I'm a tuple with two elements: $first & $second"
65+
case (first, second, third) => s"I'm a tuple with three elements: $first & $second & $third"
66+
case _ => s"Unrecognized pattern. My value: $tuple"
67+
}
68+
}
69+
70+
def typedPatternMatching(any: Any): String = {
71+
any match {
72+
case string: String => s"I'm a string. My value: $string"
73+
case integer: Int => s"I'm an integer. My value: $integer"
74+
case _ => s"I'm from an unknown type. My value: $any"
75+
}
76+
}
77+
78+
def regexPatterns(toMatch: String): String = {
79+
val numeric = """([0-9]+)""".r
80+
val alphabetic = """([a-zA-Z]+)""".r
81+
val alphanumeric = """([a-zA-Z0-9]+)""".r
82+
83+
toMatch match {
84+
case numeric(value) => s"I'm a numeric with value $value"
85+
case alphabetic(value) => s"I'm an alphabetic with value $value"
86+
case alphanumeric(value) => s"I'm an alphanumeric with value $value"
87+
case _ => s"I contain other characters than alphanumerics. My value $toMatch"
88+
}
89+
}
90+
91+
def optionsPatternMatching(option: Option[String]): String = {
92+
option match {
93+
case Some(value) => s"I'm not an empty option. Value $value"
94+
case None => "I'm an empty option"
95+
}
96+
}
97+
98+
def patternGuards(toMatch: Any, maxLength: Int): String = {
99+
toMatch match {
100+
case list: List[Any] if (list.size <= maxLength) => "List is of acceptable size"
101+
case list: List[Any] => "List has not an acceptable size"
102+
case string: String if (string.length <= maxLength) => "String is of acceptable size"
103+
case string: String => "String has not an acceptable size"
104+
case _ => "Input is neither a List or a String"
105+
}
106+
}
107+
108+
def sealedClass(cardSuit: CardSuit): String = {
109+
cardSuit match {
110+
case Spike() => "Card is spike"
111+
case Club() => "Card is club"
112+
case Heart() => "Card is heart"
113+
case Diamond() => "Card is diamond"
114+
}
115+
}
116+
117+
def extractors(person: Any): String = {
118+
person match {
119+
case Person(initials) => s"My initials are $initials"
120+
case _ => "Could not extract initials"
121+
}
122+
}
123+
124+
def closuresPatternMatching(list: List[Any]): List[Any] = {
125+
list.collect { case i: Int if (i < 10) => i }
126+
}
127+
128+
def catchBlocksPatternMatching(exception: Exception): String = {
129+
try {
130+
throw exception
131+
} catch {
132+
case ex: IllegalArgumentException => "It's an IllegalArgumentException"
133+
case ex: RuntimeException => "It's a RuntimeException"
134+
case _ => "It's an unknown kind of exception"
135+
}
136+
}
137+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package com.baeldung.scala
2+
3+
import java.io.FileNotFoundException
4+
5+
import org.junit.Assert.assertEquals
6+
import org.junit.Test
7+
8+
class PatternMatchingUnitTest {
9+
@Test
10+
def whenAMammalIsGivenToTheMatchExpression_ThenItsRecognizedAsMammal(): Unit = {
11+
val result = new PatternMatching().caseClassesPatternMatching(Mammal("Lion", fromSea = false))
12+
assertEquals("I'm a Lion, a kind of mammal. Am I from the sea? false", result)
13+
}
14+
15+
@Test
16+
def whenABirdIsGivenToTheMatchExpression_ThenItsRecognizedAsBird(): Unit = {
17+
val result = new PatternMatching().caseClassesPatternMatching(Bird("Pigeon"))
18+
assertEquals("I'm a Pigeon, a kind of bird", result)
19+
}
20+
21+
@Test
22+
def whenAnUnkownAnimalIsGivenToTheMatchExpression_TheDefaultClauseIsUsed(): Unit = {
23+
val result = new PatternMatching().caseClassesPatternMatching(Fish("Tuna"))
24+
assertEquals("I'm an unknown animal", result)
25+
}
26+
27+
@Test
28+
def whenTheConstantZeroIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
29+
val result = new PatternMatching().constantsPatternMatching(0)
30+
assertEquals("I'm equal to zero", result)
31+
}
32+
33+
@Test
34+
def whenFourAndAHalfIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
35+
val result = new PatternMatching().constantsPatternMatching(4.5d)
36+
assertEquals("I'm a double", result)
37+
}
38+
39+
@Test
40+
def whenTheBooleanFalseIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
41+
val result = new PatternMatching().constantsPatternMatching(false)
42+
assertEquals("I'm the contrary of true", result)
43+
}
44+
45+
@Test
46+
def whenAnUnkownConstantIsPassed_ThenTheDefaultPatternIsUsed(): Unit = {
47+
val result = new PatternMatching().constantsPatternMatching(true)
48+
assertEquals("I'm unknown and equal to true", result)
49+
}
50+
51+
@Test
52+
def whenASingleElementListIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
53+
val result = new PatternMatching().sequencesPatternMatching(List("String"))
54+
assertEquals("I'm a list with one element: String", result)
55+
}
56+
57+
@Test
58+
def whenAMultipleElementsListIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
59+
val result = new PatternMatching().sequencesPatternMatching(List("Multiple", "Elements"))
60+
assertEquals("I'm a list with one or multiple elements: List(Multiple, Elements)", result)
61+
}
62+
63+
@Test
64+
def whenAVectorBeginningWithOneAndTwoIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
65+
val result = new PatternMatching().sequencesPatternMatching(Vector(1, 2, 3))
66+
assertEquals("I'm a vector: Vector(1, 2, 3)", result)
67+
}
68+
69+
@Test
70+
def whenANotMatchingVectorIsPassed_ThenItShouldntMatchAndEnterTheDefaultClause(): Unit = {
71+
val result = new PatternMatching().sequencesPatternMatching(Vector(2, 1))
72+
assertEquals("I'm an unrecognized sequence. My value: Vector(2, 1)", result)
73+
}
74+
75+
@Test
76+
def whenAnEmptyListIsPassed_ThenItShouldntMatchAndEnterTheDefaultClause(): Unit = {
77+
val result = new PatternMatching().sequencesPatternMatching(List())
78+
assertEquals("I'm an unrecognized sequence. My value: List()", result)
79+
}
80+
81+
@Test
82+
def whenATwoElementsTupleIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
83+
val result = new PatternMatching().tuplesPatternMatching(("First", "Second"))
84+
assertEquals("I'm a tuple with two elements: First & Second", result)
85+
}
86+
87+
@Test
88+
def whenAThreeElementsTupleIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
89+
val result = new PatternMatching().tuplesPatternMatching(("First", "Second", "Third"))
90+
assertEquals("I'm a tuple with three elements: First & Second & Third", result)
91+
}
92+
93+
@Test
94+
def whenAnoterKindOfTupleIsPassed_ThenItShouldntMatchAndReturnTheDefaultPattern(): Unit = {
95+
val result = new PatternMatching().tuplesPatternMatching(("First"))
96+
assertEquals("Unrecognized pattern. My value: First", result)
97+
}
98+
99+
@Test
100+
def whenAStringConsistingOfNumericsOnlyIsPassed_ThenItShouldMatchTheNumericRegex(): Unit = {
101+
val result = new PatternMatching().regexPatterns("123")
102+
assertEquals("I'm a numeric with value 123", result)
103+
}
104+
105+
@Test
106+
def whenAStringConsistignOfAlphabeticsOnlyIsPassed_ThenItShouldMatchTheAlphabeticRegex(): Unit = {
107+
val result = new PatternMatching().regexPatterns("abc")
108+
assertEquals("I'm an alphabetic with value abc", result)
109+
}
110+
111+
@Test
112+
def whenAStringConsistignOfAlphanumericsOnlyIsPassed_ThenItShouldMatchTheAlphanumericRegex(): Unit = {
113+
val result = new PatternMatching().regexPatterns("abc123")
114+
assertEquals("I'm an alphanumeric with value abc123", result)
115+
}
116+
117+
@Test
118+
def whenAnotherTypeOfStringIsPassed_ThenItShouldntMatchAndReturnTheDefaultPattern(): Unit = {
119+
val result = new PatternMatching().regexPatterns("abc_123")
120+
assertEquals("I contain other characters than alphanumerics. My value abc_123", result)
121+
}
122+
123+
@Test
124+
def whenAFilledOptionIsPassed_ThenItShouldMatchTheSomeClause(): Unit = {
125+
val result = new PatternMatching().optionsPatternMatching(Option.apply("something"))
126+
assertEquals("I'm not an empty option. Value something", result)
127+
}
128+
129+
@Test
130+
def whenAnEmptyOptionIsPassed_ThenItShouldMatchTheNoneClause(): Unit = {
131+
val result = new PatternMatching().optionsPatternMatching(Option.empty)
132+
assertEquals("I'm an empty option", result)
133+
}
134+
135+
@Test
136+
def whenAListWithAcceptedSizeIsPassed_ThenThePositiveMessageIsSent(): Unit = {
137+
val result = new PatternMatching().patternGuards(List(1, 2), 3)
138+
assertEquals("List is of acceptable size", result)
139+
}
140+
141+
@Test
142+
def whenAListWithAnUnacceptedSizeIsPassed_ThenTheNegativeMessageIsSent(): Unit = {
143+
val result = new PatternMatching().patternGuards(List(1, 2, 3, 4), 3)
144+
assertEquals("List has not an acceptable size", result)
145+
}
146+
147+
@Test
148+
def whenAStringWithAcceptedSizeIsPassed_ThenThePositiveMessageIsSent(): Unit = {
149+
val result = new PatternMatching().patternGuards("OK", 3)
150+
assertEquals("String is of acceptable size", result)
151+
}
152+
153+
@Test
154+
def whenAStringWithAnUnacceptedSizeIsPassed_ThenTheNegativeMessageIsSent(): Unit = {
155+
val result = new PatternMatching().patternGuards("Not OK", 3)
156+
assertEquals("String has not an acceptable size", result)
157+
}
158+
159+
@Test
160+
def whenAnObjectWhichIsNotAListOrAStringIsPassed_thenTheDefaultClauseIsUsed(): Unit = {
161+
val result = new PatternMatching().patternGuards(1, 1)
162+
assertEquals("Input is neither a List or a String", result)
163+
}
164+
165+
@Test
166+
def whenACardSuitIsPassed_ThenTheCorrespondingMatchCaseClauseIsUsed(): Unit = {
167+
assertEquals("Card is spike", new PatternMatching().sealedClass(Spike()))
168+
assertEquals("Card is club", new PatternMatching().sealedClass(Club()))
169+
assertEquals("Card is heart", new PatternMatching().sealedClass(Heart()))
170+
assertEquals("Card is diamond", new PatternMatching().sealedClass(Diamond()))
171+
}
172+
173+
@Test
174+
def whenAnObjectWithExtractorIsPassed_ThenTheExtractedValueIsUsedInTheCaseClause(): Unit = {
175+
val person = Person("John Smith")
176+
val result = new PatternMatching().extractors(person)
177+
assertEquals("My initials are J. S.", result)
178+
}
179+
180+
@Test
181+
def whenAnObjectWithExtractorIsPassed_AndTheValueIsEmpty_ThenTheDefaultCaseClauseIsUsed(): Unit = {
182+
val person = Person("")
183+
val result = new PatternMatching().extractors(person)
184+
assertEquals("Could not extract initials", result)
185+
}
186+
187+
@Test
188+
def whenAListOfRandomElementsIsPassed_ThenOnlyTheIntegersBelowTenAreReturned(): Unit = {
189+
val input = List(1, 2, "5", 11, true)
190+
val result = new PatternMatching().closuresPatternMatching(input)
191+
assertEquals(List(1, 2), result)
192+
}
193+
194+
@Test
195+
def whenAnExceptionIsPassed_ThenTheCorrespondingMessageIsReturned(): Unit = {
196+
val pm = new PatternMatching()
197+
198+
val iae = new IllegalArgumentException()
199+
val re = new RuntimeException()
200+
val fnfe = new FileNotFoundException()
201+
202+
assertEquals("It's an IllegalArgumentException", pm.catchBlocksPatternMatching(iae))
203+
assertEquals("It's a RuntimeException", pm.catchBlocksPatternMatching(re))
204+
assertEquals("It's an unknown kind of exception", pm.catchBlocksPatternMatching(fnfe))
205+
}
206+
}
207+
208+

0 commit comments

Comments
 (0)