BAEL-3533 - Scala Pattern Matching (Switch/Case) (#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)
This commit is contained in:
YassinHajaj 2019-11-29 20:33:59 +01:00 committed by Sam Millington
parent b6826f8c6e
commit 32fa178c18
2 changed files with 345 additions and 0 deletions

View File

@ -0,0 +1,137 @@
package com.baeldung.scala
// Case Class
abstract class Animal
case class Mammal(name: String, fromSea: Boolean) extends Animal
case class Bird(name: String) extends Animal
case class Fish(name: String) extends Animal
// Sealed Class
sealed abstract class CardSuit
case class Spike() extends CardSuit
case class Diamond() extends CardSuit
case class Heart() extends CardSuit
case class Club() extends CardSuit
object Person {
def apply(fullName: String) = fullName
def unapply(fullName: String): Option[String] = {
if (!fullName.isEmpty)
Some(fullName.replaceAll("(?<=\\w)(\\w+)", "."))
else
None
}
}
class PatternMatching {
def caseClassesPatternMatching(animal: Animal): String = {
animal match {
case Mammal(name, fromSea) => s"I'm a $name, a kind of mammal. Am I from the sea? $fromSea"
case Bird(name) => s"I'm a $name, a kind of bird"
case _ => "I'm an unknown animal"
}
}
def constantsPatternMatching(constant: Any): String = {
constant match {
case 0 => "I'm equal to zero"
case 4.5d => "I'm a double"
case false => "I'm the contrary of true"
case _ => s"I'm unknown and equal to $constant"
}
}
def sequencesPatternMatching(sequence: Any): String = {
sequence match {
case List(singleElement) => s"I'm a list with one element: $singleElement"
case List(_, _*) => s"I'm a list with one or multiple elements: $sequence"
case Vector(1, 2, _*) => s"I'm a vector: $sequence"
case _ => s"I'm an unrecognized sequence. My value: $sequence"
}
}
def tuplesPatternMatching(tuple: Any): String = {
tuple match {
case (first, second) => s"I'm a tuple with two elements: $first & $second"
case (first, second, third) => s"I'm a tuple with three elements: $first & $second & $third"
case _ => s"Unrecognized pattern. My value: $tuple"
}
}
def typedPatternMatching(any: Any): String = {
any match {
case string: String => s"I'm a string. My value: $string"
case integer: Int => s"I'm an integer. My value: $integer"
case _ => s"I'm from an unknown type. My value: $any"
}
}
def regexPatterns(toMatch: String): String = {
val numeric = """([0-9]+)""".r
val alphabetic = """([a-zA-Z]+)""".r
val alphanumeric = """([a-zA-Z0-9]+)""".r
toMatch match {
case numeric(value) => s"I'm a numeric with value $value"
case alphabetic(value) => s"I'm an alphabetic with value $value"
case alphanumeric(value) => s"I'm an alphanumeric with value $value"
case _ => s"I contain other characters than alphanumerics. My value $toMatch"
}
}
def optionsPatternMatching(option: Option[String]): String = {
option match {
case Some(value) => s"I'm not an empty option. Value $value"
case None => "I'm an empty option"
}
}
def patternGuards(toMatch: Any, maxLength: Int): String = {
toMatch match {
case list: List[Any] if (list.size <= maxLength) => "List is of acceptable size"
case list: List[Any] => "List has not an acceptable size"
case string: String if (string.length <= maxLength) => "String is of acceptable size"
case string: String => "String has not an acceptable size"
case _ => "Input is neither a List or a String"
}
}
def sealedClass(cardSuit: CardSuit): String = {
cardSuit match {
case Spike() => "Card is spike"
case Club() => "Card is club"
case Heart() => "Card is heart"
case Diamond() => "Card is diamond"
}
}
def extractors(person: Any): String = {
person match {
case Person(initials) => s"My initials are $initials"
case _ => "Could not extract initials"
}
}
def closuresPatternMatching(list: List[Any]): List[Any] = {
list.collect { case i: Int if (i < 10) => i }
}
def catchBlocksPatternMatching(exception: Exception): String = {
try {
throw exception
} catch {
case ex: IllegalArgumentException => "It's an IllegalArgumentException"
case ex: RuntimeException => "It's a RuntimeException"
case _ => "It's an unknown kind of exception"
}
}
}

View File

@ -0,0 +1,208 @@
package com.baeldung.scala
import java.io.FileNotFoundException
import org.junit.Assert.assertEquals
import org.junit.Test
class PatternMatchingUnitTest {
@Test
def whenAMammalIsGivenToTheMatchExpression_ThenItsRecognizedAsMammal(): Unit = {
val result = new PatternMatching().caseClassesPatternMatching(Mammal("Lion", fromSea = false))
assertEquals("I'm a Lion, a kind of mammal. Am I from the sea? false", result)
}
@Test
def whenABirdIsGivenToTheMatchExpression_ThenItsRecognizedAsBird(): Unit = {
val result = new PatternMatching().caseClassesPatternMatching(Bird("Pigeon"))
assertEquals("I'm a Pigeon, a kind of bird", result)
}
@Test
def whenAnUnkownAnimalIsGivenToTheMatchExpression_TheDefaultClauseIsUsed(): Unit = {
val result = new PatternMatching().caseClassesPatternMatching(Fish("Tuna"))
assertEquals("I'm an unknown animal", result)
}
@Test
def whenTheConstantZeroIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().constantsPatternMatching(0)
assertEquals("I'm equal to zero", result)
}
@Test
def whenFourAndAHalfIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().constantsPatternMatching(4.5d)
assertEquals("I'm a double", result)
}
@Test
def whenTheBooleanFalseIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().constantsPatternMatching(false)
assertEquals("I'm the contrary of true", result)
}
@Test
def whenAnUnkownConstantIsPassed_ThenTheDefaultPatternIsUsed(): Unit = {
val result = new PatternMatching().constantsPatternMatching(true)
assertEquals("I'm unknown and equal to true", result)
}
@Test
def whenASingleElementListIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().sequencesPatternMatching(List("String"))
assertEquals("I'm a list with one element: String", result)
}
@Test
def whenAMultipleElementsListIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().sequencesPatternMatching(List("Multiple", "Elements"))
assertEquals("I'm a list with one or multiple elements: List(Multiple, Elements)", result)
}
@Test
def whenAVectorBeginningWithOneAndTwoIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().sequencesPatternMatching(Vector(1, 2, 3))
assertEquals("I'm a vector: Vector(1, 2, 3)", result)
}
@Test
def whenANotMatchingVectorIsPassed_ThenItShouldntMatchAndEnterTheDefaultClause(): Unit = {
val result = new PatternMatching().sequencesPatternMatching(Vector(2, 1))
assertEquals("I'm an unrecognized sequence. My value: Vector(2, 1)", result)
}
@Test
def whenAnEmptyListIsPassed_ThenItShouldntMatchAndEnterTheDefaultClause(): Unit = {
val result = new PatternMatching().sequencesPatternMatching(List())
assertEquals("I'm an unrecognized sequence. My value: List()", result)
}
@Test
def whenATwoElementsTupleIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().tuplesPatternMatching(("First", "Second"))
assertEquals("I'm a tuple with two elements: First & Second", result)
}
@Test
def whenAThreeElementsTupleIsPassed_ThenItMatchesTheCorrespondingPattern(): Unit = {
val result = new PatternMatching().tuplesPatternMatching(("First", "Second", "Third"))
assertEquals("I'm a tuple with three elements: First & Second & Third", result)
}
@Test
def whenAnoterKindOfTupleIsPassed_ThenItShouldntMatchAndReturnTheDefaultPattern(): Unit = {
val result = new PatternMatching().tuplesPatternMatching(("First"))
assertEquals("Unrecognized pattern. My value: First", result)
}
@Test
def whenAStringConsistingOfNumericsOnlyIsPassed_ThenItShouldMatchTheNumericRegex(): Unit = {
val result = new PatternMatching().regexPatterns("123")
assertEquals("I'm a numeric with value 123", result)
}
@Test
def whenAStringConsistignOfAlphabeticsOnlyIsPassed_ThenItShouldMatchTheAlphabeticRegex(): Unit = {
val result = new PatternMatching().regexPatterns("abc")
assertEquals("I'm an alphabetic with value abc", result)
}
@Test
def whenAStringConsistignOfAlphanumericsOnlyIsPassed_ThenItShouldMatchTheAlphanumericRegex(): Unit = {
val result = new PatternMatching().regexPatterns("abc123")
assertEquals("I'm an alphanumeric with value abc123", result)
}
@Test
def whenAnotherTypeOfStringIsPassed_ThenItShouldntMatchAndReturnTheDefaultPattern(): Unit = {
val result = new PatternMatching().regexPatterns("abc_123")
assertEquals("I contain other characters than alphanumerics. My value abc_123", result)
}
@Test
def whenAFilledOptionIsPassed_ThenItShouldMatchTheSomeClause(): Unit = {
val result = new PatternMatching().optionsPatternMatching(Option.apply("something"))
assertEquals("I'm not an empty option. Value something", result)
}
@Test
def whenAnEmptyOptionIsPassed_ThenItShouldMatchTheNoneClause(): Unit = {
val result = new PatternMatching().optionsPatternMatching(Option.empty)
assertEquals("I'm an empty option", result)
}
@Test
def whenAListWithAcceptedSizeIsPassed_ThenThePositiveMessageIsSent(): Unit = {
val result = new PatternMatching().patternGuards(List(1, 2), 3)
assertEquals("List is of acceptable size", result)
}
@Test
def whenAListWithAnUnacceptedSizeIsPassed_ThenTheNegativeMessageIsSent(): Unit = {
val result = new PatternMatching().patternGuards(List(1, 2, 3, 4), 3)
assertEquals("List has not an acceptable size", result)
}
@Test
def whenAStringWithAcceptedSizeIsPassed_ThenThePositiveMessageIsSent(): Unit = {
val result = new PatternMatching().patternGuards("OK", 3)
assertEquals("String is of acceptable size", result)
}
@Test
def whenAStringWithAnUnacceptedSizeIsPassed_ThenTheNegativeMessageIsSent(): Unit = {
val result = new PatternMatching().patternGuards("Not OK", 3)
assertEquals("String has not an acceptable size", result)
}
@Test
def whenAnObjectWhichIsNotAListOrAStringIsPassed_thenTheDefaultClauseIsUsed(): Unit = {
val result = new PatternMatching().patternGuards(1, 1)
assertEquals("Input is neither a List or a String", result)
}
@Test
def whenACardSuitIsPassed_ThenTheCorrespondingMatchCaseClauseIsUsed(): Unit = {
assertEquals("Card is spike", new PatternMatching().sealedClass(Spike()))
assertEquals("Card is club", new PatternMatching().sealedClass(Club()))
assertEquals("Card is heart", new PatternMatching().sealedClass(Heart()))
assertEquals("Card is diamond", new PatternMatching().sealedClass(Diamond()))
}
@Test
def whenAnObjectWithExtractorIsPassed_ThenTheExtractedValueIsUsedInTheCaseClause(): Unit = {
val person = Person("John Smith")
val result = new PatternMatching().extractors(person)
assertEquals("My initials are J. S.", result)
}
@Test
def whenAnObjectWithExtractorIsPassed_AndTheValueIsEmpty_ThenTheDefaultCaseClauseIsUsed(): Unit = {
val person = Person("")
val result = new PatternMatching().extractors(person)
assertEquals("Could not extract initials", result)
}
@Test
def whenAListOfRandomElementsIsPassed_ThenOnlyTheIntegersBelowTenAreReturned(): Unit = {
val input = List(1, 2, "5", 11, true)
val result = new PatternMatching().closuresPatternMatching(input)
assertEquals(List(1, 2), result)
}
@Test
def whenAnExceptionIsPassed_ThenTheCorrespondingMessageIsReturned(): Unit = {
val pm = new PatternMatching()
val iae = new IllegalArgumentException()
val re = new RuntimeException()
val fnfe = new FileNotFoundException()
assertEquals("It's an IllegalArgumentException", pm.catchBlocksPatternMatching(iae))
assertEquals("It's a RuntimeException", pm.catchBlocksPatternMatching(re))
assertEquals("It's an unknown kind of exception", pm.catchBlocksPatternMatching(fnfe))
}
}