Scala --- option type and partial function, exception handling, regular expression

Keywords: Scala Big Data Hadoop

1. Pattern matching

Scala has a very powerful pattern matching mechanism and is widely used, such as:

  • Judge fixed value
  • Type query
  • Get data quickly

1.1 simple pattern matching

A pattern matching contains a series of alternatives, each of which starts with the keyword case. Each alternative contains a pattern and one or more expressions. The arrow symbol = > separates the pattern from the expression.

variable match {
    case "Constant 1" => Expression 1
    case "Constant 2" => Expression 2
    case "Constant 3" => Expression 3
    case _ => Expression 4 // Default matches
}

Execution process

  1. First execute the first case to see whether the variable value is consistent with the constant value corresponding to the case
  2. If consistent, execute the expression corresponding to the case
  3. If not, execute the next case later to see if the variable value is consistent with the constant value corresponding to the case
  4. And so on, if all cases do not match, the case is executed_ Corresponding expression

Example

import scala.io.StdIn

//Case: simple matching of pattern matching
object ClassDemo01 {
  def main(args: Array[String]): Unit = {
    //1. Prompt the user to enter a string and receive it
    println("Please enter a string: ")
    var str = StdIn.readLine()
    //2. Judge whether the string is the specified content and receive the result
    val result = str match {
      case "hadoop" => "Big data distributed storage and computing framework"
      case "zookeeper" => "Big data distributed coordination service framework"
      case "spark" => "Big data distributed memory computing framework"
      case _ => "Unmatched"
    }
    //3. Print results
    println(result)
    println("-" * 15) //Split line
    //Abbreviated form
    str match {
      case "hadoop" => println("Big data distributed storage and computing framework")
      case "zookeeper" => println("Big data distributed coordination service framework")
      case "spark" => println("Big data distributed memory computing framework")
      case _ => println("Unmatched")
    }
  }
}

1.2 matching type

In addition to matching data, match expressions can also perform type matching. If we want to execute different logic according to different data types, we can also use match expressions.

Object name match {
    case Variable name 1: Type 1 => Expression 1
    case Variable name 2: Type 2 => Expression 2
    case Variable name 3: Type 3 => Expression 3
    ...
    case _ => Expression 4
}
	
  • Note: if the matched variable does not need to be used in the case expression, the underscore can be used instead

Example

//Case: matching type of pattern matching
object ClassDemo02 {
  def main(args: Array[String]): Unit = {
    //1. Define a variable as Any type, and then assign it "hadoop", 1 and 1.0 respectively
    val a: Any = 1.0
    //2. Define pattern matching, and then print the name of the type respectively
    val result = a match {
      case x: String => s"${x} yes String Type of data"
      case x: Double => s"${x} yes Double Type of data"
      case x: Int => s"${x} yes Int Type of data"
      case _ => "Unmatched"
    }
    //3. Print results
    println(result)
    //4. The optimized version can be used if the variable is not used during case verification_ replace.
    val result2 = a match {
      case _: String => "String"
      case _: Double => "Double"
      case _: Int => "Int"
      case _ => "Unmatched"
    }
    //Print results
    println(result2)
  }
}

1.3 guard

The so-called guard means adding if conditional judgment to the case statement, which can make our code more concise and elegant

variable match {
    case Variable name if Condition 1 => Expression 1
    case Variable name if Condition 2 => Expression 2
    case Variable name if Condition 3 => Expression 3
    ...
    case _ => Expression 4
}

Example

import scala.io.StdIn

//Case: guard of pattern matching
object ClassDemo03 {
  def main(args: Array[String]): Unit = {
    //1. Read a number a from the console (using StdIn.readInt)
    println("Please enter an integer: ")
    var num = StdIn.readInt()
    //2. Pattern matching
    num match {
      //2.1 if a > = 0 and a < = 3, print [0-3]
      case a if a >= 0 && a <= 3 => println("[0-3]")
      //2.2 if a > = 4 and a < = 8, print [4,8]
      case a if a >= 4 && a <= 8 => println("[4-8]")
      //2.3 otherwise, the print does not match
      case _ => println("Unmatched")
    }
  }
}

1.4 matching sample classes

In Scala, pattern matching can be used to match the sample class, so that the member data in the sample class can be quickly obtained. Later, we will often use it when developing the Akka case.

Object name match {
    case Sample type 1(Field 1, Field 2, field n) => Expression 1
    case Sample type 2(Field 1, Field 2, field n) => Expression 2
    case Sample type 3(Field 1, Field 2, field n) => Expression 3
    ...
    case _ => Expression 4
}
  1. In the parentheses after the sample type, the number of fields written should be consistent with that of the sample class
  2. When pattern matching is performed through match, the object to be matched must be declared as Any type

Example

//Case: pattern matching sample class
object ClassDemo04 {

  //1. Create two sample classes Customer and Order
  //1.1 Customer includes name and age fields
  case class Customer(var name: String, var age: Int)

  //1.2 the order contains the id field
  case class Order(id: Int)

  def main(args: Array[String]): Unit = {
    //2. Define the objects of two case classes and specify them as Any type
    val c: Any = Customer("Sugar sugar", 73)
    val o: Any = Order(123)
    val arr: Any = Array(0, 1)
    //3. Match the two objects with patterns and print their member variable values respectively
    c match {
      case Customer(a, b) => println(s"Customer Object of type, name=${a}, age=${b}")
      case Order(c) => println(s"Order type, id=${c}")
      case _ => println("Unmatched")
    }
  }
}

1.5 matching set

In addition to the above functions, pattern matching in Scala can also be used to match arrays, tuples, sets (lists, sets, mappings), etc.

Array(1,x,y) // Starting with 1, the following two elements are not fixed
Array(0) // Elements that match only one 0 element
Array(0, ...) // You can have any number, but start with 0

Example

//Case: pattern matching array
object ClassDemo05 {
  def main(args: Array[String]): Unit = {
    //1. Define three arrays
    val arr1 = Array(1, 2, 3)
    val arr2 = Array(0)
    val arr3 = Array(1, 2, 3, 4, 5)
    //2. Find the specified array through pattern matching
    arr2 match {
      //Match: the length is 3, the first element is 1, and the last two elements don't matter
      case Array(1, x, y) => println(s"The matching length is 3, The first element is 1, The last two elements are: ${x}, ${y}")
      //Match: an array with only one 0 element
      case Array(0) => println("matching: An array with only one 0 element")
      //Match: the first element is 1, and the following elements are indifferent arrays
      case Array(1, _*) => println("matching: The first element is 1, An array whose trailing elements don't matter")
      //Other check items
      case _ => println("Unmatched")
    }
  }
}
List(0) // Save 0 a list of only one element
List(0,...) // The number of lists starting with 0 is not fixed
List(x,y) // A list that contains only two elements
//Case: matching list of pattern matching
object ClassDemo06 {
  def main(args: Array[String]): Unit = {
    //1. Definition list
    var list1 = List(0)
    var list2 = List(0, 1, 2, 3, 4, 5)
    var list3 = List(1, 2)
    //2. Pattern matching through match
    //Idea 1: implement it through List()
    list1 match {
      case List(0) => println("matching: List with only one 0 element")
      case List(0, _*) => println("matching: 0 start, The following elements don't care about the list")
      case List(x, y) => println(s"matching: A list of only two elements, Element is: ${x}, ${y}")
      case _ => println("Unmatched")
    }
    //Idea 2: use keywords to optimize nil and tail
    list1 match {
      case 0 :: Nil => println("matching: List with only one 0 element")
      case 0 :: tail => println("matching: 0 start, The following elements don't care about the list")
      case x :: y :: Nil => println(s"matching: A list of only two elements, Element is: ${x}, ${y}")
      case _ => println("Unmatched")
    }
  }
}

Match Yuanzu

(1, x, y) // A tuple of three elements starting with 1
(x, y, 5) // There are three elements, and the last element is a tuple of 5

Example

//Case: matching tuple of pattern matching
object ClassDemo07 {
  def main(args: Array[String]): Unit = {
    //1. Define two tuples
    val a = (1, 2, 3)
    val b = (3, 4, 5)
    val c = (3, 4)
    //2. Match the specified elements through pattern matching
    a match {
      case (1, x, y) => println(s"matching: Length 3, Start with 1, The last two elements have no tuples, Here are the last two elements
        yes: $ {x}, ${y}")
      case (x, y, 5) => println(s"matching: Length 3, End with 5, The first two elements don't matter, Here are the first two elements
        yes: $ {x}, ${y}")
      case _ => println("Unmatched")
    }
  }
}

1.6 pattern matching in variable declaration

When defining variables, you can use pattern matching to quickly obtain data. For example, quickly obtain data from arrays and lists

Example

//Case: demonstrate pattern matching in variable declaration
object ClassDemo08 {
  def main(args: Array[String]): Unit = {
    //1. Generate an array containing 0-10 numbers, and use pattern matching to obtain the second, third and fourth elements respectively
    //1.1 generate an array containing 0-10 numbers
    val arr = (0 to 10).toArray
    //1.2 use pattern matching to obtain the second, third and fourth elements respectively
    val Array(_, x, y, z, _*) = arr;
    //1.3 print results
    println(x, y, z)
    println("-" * 15)
    //2. Generate a list containing 0-10 numbers, and use pattern matching to obtain the first and second elements respectively
    //2.1 generate a list containing 0-10 numbers,
    val list = (0 to 10).toList
    //2.2 use pattern matching to obtain the first and second elements respectively
    //Idea 1: List() implementation
    val List(a, b, _*) = list
    //Idea 2: tail implementation
    val c :: d :: tail = list
    //2.3 print results
    println(a, b)
    println(c, d)
  }
}

1.7 match for expression

Scala can also use pattern matching to match for expressions, so as to quickly obtain the specified data and make our code look more concise and elegant

Example

//Case: for expression for pattern matching
object ClassDemo09 {
  def main(args: Array[String]): Unit = {
    //1. Define variables to record the student's name and age
    val map1 = Map("Zhang San" -> 23, "Li Si" -> 24, "Wang Wu" -> 23, "Zhao Liu" -> 26)
    //2. Obtain information about all students aged 23
    //2.1 format 1: realized by if statement
    for ((k, v) <- map1 if v == 23) println(s"${k} = ${v}")
    //Split line
    println("-" * 15)
    //2.2 format 2: realized by fixed value
    for ((k, 23) <- map1) println(k + " = 23")
  }
}

2. Option type

2.1 general

In actual development, it is inevitable to encounter null pointer exception when returning some data. It is relatively cumbersome to deal with it once. In Scala, when we return some data, we can return an object of Option type to encapsulate specific data, so as to effectively avoid null pointer exception.

In Scala, the Option type represents an optional value. There are two forms of this type of data:

  • Some(x): represents the actual value

  • None: indicates no value

    be careful: use getOrElse Method when the value is None You can specify a default value.
    

Example

//Case: demonstrating Option types
object ClassDemo10 {
  //1. Define a method to divide two numbers, and use Option type to encapsulate the result
  def div(a: Int, b: Int) = {
    if (b == 0) {
      None //Divisor 0, no result
    } else {
      Some(a / b) //If the divisor is not 0, the specific result will be returned
    }
  }

  def main(args: Array[String]): Unit = {
    //2. Then use pattern matching to print the results
    val result = div(10, 0)
    //Idea 1: print the results through pattern matching
    result match {
      //Not divide by zero, print the result
      case Some(x) => println(x)
      //Divide by zero printing exception error
      case None => println("Divisor cannot be 0")
    }
    println("-" * 15)
    //Idea 2: it is implemented by getOrElse() method
    println(result.getOrElse(0))
  }
}

3. Partial function

3.1 definitions

Partial functions provide A more concise syntax and simplify the definition of functions. With the functional programming of set, the code can be more elegant. The so-called partial function refers to A group of case statements wrapped in curly braces without match. The partial function is an instance object of PartialFunction[A, B], where A represents the input parameter type and B represents the return result type

3.2 format

val Object name = { //The pair of braces and a set of case statements inside them form a partial function
    case Value 1 => Expression 1
    case Value 2 => Expression 2
    case Value 3 => Expression 3
    ...
}

Example

//Case: demonstration of partial function
object ClassDemo11 {
  def main(args: Array[String]): Unit = {
    //1. Define a partial function and return it according to the specified format
    val pf: PartialFunction[Int, String] = {
      case 1 => "one"
      case 2 => "two"
      case 3 => "three"
      case _ => "other"
    }
    //2. Call method
    println(pf(1))
    println(pf(2))
    println(pf(3))
    println(pf(4))
  }
}

3.4 example 2: combined with map function

Example

//Case: partial function use, combined with map function
object ClassDemo12 {
  def main(args: Array[String]): Unit = {
    //1. Define a list containing numbers from 1 to 10
    val list1 = (1 to 10).toList
    //Core: use partial function combined with map for pattern matching
    val list2 = list1.map {
      //2 please convert all numbers from 1-3 to [1-3]
      case x if x >= 1 && x <= 3 => "[1-3]"
      //3 please convert the numbers from 4-8 to [4-8]
      case x if x >= 4 && x <= 8 => "[4-8]"
      //4 convert other numbers to (8 - *]
      case _ => "(8-*]"
    }
    //5. Print results
    println(list2)
  }
}

4. Regular expression

4.1 General

The so-called regular expression refers to the correct formula that conforms to specific rules. It is an independent language and can be compatible with most programming languages. In scala, regular expressions can be easily used to match data. The details are as follows:

  1. Regex class is provided in Scala to define regular expressions
  2. To construct a Regex object, simply use the r method of the String class
  3. It is recommended to use three double quotation marks to represent the regular expression, otherwise you will have to escape the backslash in the regular expression

4.2 format

val Regular object name = """Specific regular expressions""".r
 be careful: use findAllMatchIn Method can obtain all regular matching data(character string).

Example

//Case: check whether the mailbox is legal
object ClassDemo13 {
  def main(args: Array[String]): Unit = {
    //Requirement: define a regular expression to match whether the mailbox is legal
    //1. Define a string to represent the mailbox
    val email = "qq12344@163.com"
    //2. Define a regular expression to verify the mailbox
    /*
    . Represents any character
    + Quantifier, which means that the preceding character appears at least once, and it doesn't matter at most
    @ It must be a @ symbol and has no special meaning
    \. Because. Has a special meaning in regular, it needs to be transferred to make it ordinary
    */
    val regex = """.+@.+\..+""".r
    //3. Print results
    if (regex.findAllMatchIn(email).size != 0) {
      //Legal mailbox
      println(s"${email} It's a legal mailbox!")
    } else {
      println(s"${email} It's an illegal mailbox!")
    }
  }
}

Example 2

//Case: filter all illegal mailboxes
object ClassDemo14 {
  def main(args: Array[String]): Unit = {
    //1. Define the list and record the mailbox
    val emlList = List("38123845@qq.com", "a1da88123f@gmail.com", "zhansan@163.com",
      "123afadff.com")
    //2. Define regular expressions
    val regex = """.+@.+\..+""".r
    //3. Get all illegal mailboxes through the filter
    val list = emlList.filter(x => regex.findAllMatchIn(x).size == 0)
    //4. Print results
    println(list)
  }
}

Example 3

//Case: get the mailbox operator
object ClassDemo15 {
  def main(args: Array[String]): Unit = {
    //1. Define the list and record the mailbox
    val emlList = List("38123845@qq.com", "a1da88123f@gmail.com", "zhansan@163.com",
      "123afadff.com")
    //2. Define regular expressions
    val regex = """.+@(.+)\..+""".r
    //3. Match all legal mailboxes and their corresponding operators according to pattern matching
    val result = emlList.map {
      //email is every element in the EML list
      //company means: what you enclose in a regular expression with (), that is, grouped data
      case email @ regex(company) => email -> s"${company}"
      case email => email -> "Unmatched"
    }
    //4. Print results
    println(result)
  }
}

5. Exception handling

format

try {
	//Code that may cause problems
}
catch{
    case ex:Exception type 1 => //code
    case ex:Exception type 2 => //code
}
finally {
	//code
}
  1. The code in try is the business processing code we write
  2. catch indicates the code to be executed when an exception occurs
  3. In finally, you write code that will execute regardless of whether an exception occurs or not

Example

//Case: demonstrate exception handling
object ClassDemo16 {
  def main(args: Array[String]): Unit = {
    //1. Use try.catch to handle the exception that divisor is zero
    try {
      //Possible problem code
      val i = 10 / 0
    } catch {
      //Solutions to problems
      //Case ex: exception = > println ("something's wrong with the code!")
      case ex: Exception => ex.printStackTrace()
    }
    println("Hello!")
    println("-" * 15) //I am the dividing line
    //2. Throw an exception object
    throw new Exception("I am a Bug!")
    println("Hello, Scala!") //This line of code will not be executed
  }
}

6. Extractor

Overview we have used the very powerful pattern matching function in Scala before. Through pattern matching, we can quickly obtain the member variable values in the sample class object.

For example:

// 1. Create two sample classes
case class Person(name: String, age: Int)

case class Order(id: String)

def main(args: Array[String]): Unit = {
  // 2. Create a sample class object and assign it to Any type
  val zhangsan: Any = Person("Zhang San", 20)
  val order1: Any = Order("001")
  // 3. Use the match...case expression for pattern matching
  // Get member variables in the sample class
  order1 match {
    case Person(name, age) => println(s"full name: ${name} Age: ${age}")
    case Order(id1) => println(s"ID Is: ${id1}")
    case _ => println("Unmatched")
  }
}

The answer is: No. If a class wants to support pattern matching, it must implement an extractor.

1. Extractor means unapply()method .
2. The sample class is implemented automatically apply(),unapply()method, We don't need to define it manually.

6.2 format

To implement a class extractor, you only need to implement an unapply method in the associated object of the class.

def unapply(stu:Student):Option[(Type 1, Type 2, Type 3...)] = {
    if(stu != null) {
    	Some((Variable 1, Variable 2, Variable 3...))
    }
    else {
   		 None
    }
}

6.3 examples

object ClassDemo17 {

  //1. Create a Student class that contains two fields: name and age
  class Student(var name: String, var age: Int)

  //2. Implement a class extractor, use match expression for pattern matching, and extract the fields in the class.
  object Student { //Companion object
    def apply(name: String, age: Int) = new Student(name, age) //Free new
    def unapply(s: Student): Option[(String, Int)] = { //It is equivalent to disassembling an object into its properties

      if (s != null)
        Some(s.name, s.age)
      else
        None
    }
  }

  //Main method, as the main entry of the program
  def main(args: Array[String]): Unit = {
    //3. Create the object of Student class
    val s = new Student("Sugar sugar", 73) //Create objects in the normal way
    val s2 = Student("Sugar sugar", 73) //No new, create object, apply method guarantee
    //4. Print the attribute value of the object
    println(s2.name + "..." + s.age) //Get the property value of the object in the normal way
    //5. Get the method in the object through the extractor
    val result = Student.unapply(s2)
    println(result)
  }
}

Posted by KingPhilip on Tue, 30 Nov 2021 23:38:39 -0800