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:
parent
b6826f8c6e
commit
32fa178c18
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue