1. Introduction to Scala
1.1 general
Scala is a multi paradigm programming language based on JVM. Generally speaking, Scala is a functional object-oriented language running on the JVM. Scala can be widely used in various programming tasks. It can do everything from writing small scripts to building giant systems. Because of this, Scala can provide some outstanding features, such as its integration of various features of face-to-face object programming and function oriented programming, as well as a higher-level concurrency model.
JVM based explanation: Scala running environment is similar to Java and depends on JVM
Multi paradigm interpretation: Scala supports multiple programming styles
1.2 language features
Scala is object-oriented
Scala is a pure object-oriented language, and every value is an object. The data type and behavior of objects are described by classes and features. The extension of class abstraction mechanism is realized in two ways, one is subclass inheritance, the other is mixing mechanism. Both of these two ways can avoid the problem of multiple inheritance.
Scala is functional programming
Scala is also a functional language whose functions can be used as values.
Scala is compatible
Compatible with Java, you can access the huge Java class library
Scala is lean
Scala has strong expressive ability. One line of code is equal to multiple lines of Java code. It has fast development speed, which can keep your program short and clear, and look more concise and elegant
Scala is statically typed
Scala has a very advanced static type system, which ensures the security and consistency of the code through compile time inspection. Support: type inference and pattern matching
Scala can develop large instructional applications
For example: Spark, Flink program, etc
1.3 comparison between Scala program and Java program
1.3.1 comparison of procedure execution
1.3.2 code comparison
Java code
// Entity class public class People { private String name; private int age; public People(){} public People(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } // Test class public class CodeDemo { public static void main(String[] args) { People people = new People("wang",20); System.out.println(people); } }
Scala code
case class People(var name:String, var age:Int) val peolpe = People("wang",20); println(peolpe);
1.4 construction of scala environment
1.4.1 general
Scala is based on Java and uses a lot of Java class libraries and variables. There must be a Java running environment for Scala to execute correctly. To compile and run Scala programs, you need to:
JDK
Scala compiler (Scala SDK)
Next, you need to install the following in sequence:
1. Install JDK
2. Install Scala SDK
3. Install Scala plug-in in IDEA
1.4.2 installing JDK
Install jdk1 8 64 bit version, and configure the environment variables. This process is omitted.
1.4.3 installing the Scala SDK
The Scala SDK is a compiler for the Scala language. To develop Scala programs, you must first install the Scala SDK. Installation steps (example version: scala -2.11.12):
1. Download the Scala SDK
Official download address: https://www.scala-lang.org/download/
2. Install Scala SDK
2.1 double click scala - 2.11.12 MSI, install scala in the specified directory and install it as a fool. Next, next
2.2 the installation path should be legal, and there should be no special symbols such as Chinese, spaces and so on
3. Test whether the installation is successful
3.1 open the console and enter: scala - version
Scala code runner version 2.11.12 -- Copyright 2002-2017, LAMP/EPFL
3.2 start the scala interpreter, enter Scala, and verify the execution results of scala code in 1.3.2
3.3 exit the Scala interpreter, enter: quit or close the console directly
1.4.4} install IDEA Scala plug-in
IDEA does not support Scala program development by default, so you need to install Scala plug-in in IDEA to support Scala language.
First download the specified version of IDEA Scala plug-in:
- The downloaded Scala plug-in must be consistent with the locally installed version of IDEA
- Official download address: https://plugins.jetbrains.com/plugin/1347-scala
Then configure the Scala plug-in in the IDEA
Open file settings, and there is an Install plugin from disk on the plugins tab
Find the downloaded plug-in, click OK, and restart IDEA
2.Scala syntax
2.1 output statement
Mode 1: line feed output
Format: println(Statements printed to the console)
Mode 1: output without line break
Format: print(Statements printed to the console)
Note: whether println() or print(), multiple values can be printed at the same time. The format is: Print (value 1, value 2, value 3...)
2.2 semicolon
For Scala statements, the semicolon after a single line of code can be written or not written. If multiple lines of code are written on one line, the semicolon in the middle cannot be omitted, and the semicolon of the last code can be omitted or not written.
Example:
println(123) println(456);println(789)
2.3 declaration of variables
Format:
Java variable definition
int a = 0;
Variables defined in Scala have two keywords: val and var
val/var Variable name : Variable type = Initial value
Of which:
val defines variables that cannot be re assigned, that is, user-defined constants
var defines a variable that can be re assigned
Scala uses constants rather than variables to solve problems. The advantage of this is that it can reduce the safety problems of multithreading concurrency, which is especially suitable for multi concurrency and distributed scenarios.
Scala supports automatic type inference, which can automatically infer the type of variable according to the value of variable, making the code more concise.
Reference code:
scala> val name = "zhangsan" name: String = zhangsan scala> val age = 20 age: Int = 20
2.4 string
Scala provides a variety of ways to define strings
2.4.1 double quotation marks
Syntax:
val/var Variable name = ""String"
2.4.2 interpolation expression
In Scala, interpolation expressions can be used to define strings, effectively avoiding the splicing of a large number of strings
Syntax:
val/var Variable name = s"${variable/expression}"String"
explain:
·Add s before defining string
·In a string, ${} can be used to reference variables or write expressions
Example:
scala> val str1 = "a" str1: String = a scala> val str2 = "b" str2: String = b scala> val result = s"str1=${str1},str2=${str2}" result: String = str1=a,str2=b
2.4.3 three quotation marks
Use three quotation marks to define a string to save a large piece of text, which can include any character without escape
Syntax:
val/var Variable name = """String ''
Example:
Define a string and save the following SQL statement
select * from scala_customer where id = 1
Using Java definitions
String sql = "select \n" + "\t\t* \n" + "from \n" + "\t\tscala_customer \n" + "where \n" + "\t\tid = 1"; System.out.println(sql);
Using Scala definitions
val sql = """select | * |from | scala_customer |where | id = 1""" println(sql)
2.5 identifier
Identifier concept
The character sequence used by Scala in naming various variables, methods and functions is called identifier.
Any place where you can name yourself is called an identifier.
Naming rules for identifiers
The identifier declaration in Scala is basically the same as that in Java, but the details will change.
1) The first character is a letter, the following characters are any letters and numbers, dollar symbol, and can be followed by underscore_
2) Number cannot start
3) The first character is an operator (such as + - * /), and the subsequent characters also need to be followed by an operator, at least one
4) Operators (such as + - * /) cannot be in the middle and last of identifiers
5) Any string that can be included with backquotes (` `), even keywords
Identifier naming considerations
Package name: try to adopt meaningful package name, short and meaningful
Hump method is adopted for variable name, function name and method name.
"$" and "" It is best not to appear in identifiers. The "$" character is also treated as a letter, but is retained as an identifier generated by the scala compiler. The identifier in the user program should not contain the "$" character. Although it can be compiled, it may cause name collision with the identifier generated by the scala compiler.
”_” It has important uses in Scala to prevent "" The usage is confused, and it is generally not used for variable declaration.
Example:
val ++ = "123" val %@!#~ = "345" val `public` = ""
2.6 data type
Data class | describe |
Byte | 8-bit signed complement integer. The range of values is - 128 to 127 |
Short | 16 bit signed complement integer. The range of values is - 32768 to 32767 |
Int | 32-bit signed complement integer. The range of values is - 2147483648 to 2147483647 |
Long | 64 bit signed complement integer. The range of values is - 9223372036854775808 to 9223372036854775807 |
Float | 32-bit, IEEE 754 standard single precision floating-point number |
Double | 64 bit IEEE 754 standard double precision floating point number |
Char | 16 bit unsigned Unicode character with interval value of U+0000 to U+FFFF |
String | Character sequence |
Boolean | true or false |
Hierarchy chart
type | describe |
Any | Any is a supertype of all types, also known as a top-level type. It defines some general methods, such as equals, hashCode and toString. |
AnyVal | Parent of all numeric types |
AnyRef | Parent class of all object types (reference types) |
Unit | Indicates no value, which is equivalent to void in other languages. The result type used as a method that does not return any results. Unit has only one instance value, written as (). |
Null | Null is a subclass of AnyRef. Its instance is null. Null can be assigned to any object type. |
Nothing | Nothing type is at the bottom of Scala's class hierarchy; It is a subtype of any other type. |
2.7 operators
In Scala, operators are methods. Scala contains the following types of operators:
Arithmetic operator
Relational operator
Logical operator
Bitwise Operators
Assignment Operators
2.7.1 arithmetic operators
operator | operation | example | result |
+ | Plus sign | +3 | 3 |
- | minus sign | b=4; -b | -4 |
+ | plus | 5+5 | 10 |
- | reduce | 6-4 | 2 |
* | ride | 3*4 | 12 |
/ | except | 5/5 | 1 |
% | Mold taking (residual) | 7%5 | 2 |
+ | String addition | "He"+"llo" | "Hello" |
Unlike Java, Scala does not have + + - these two operators, which can achieve the same effect through + =, - =.
2.7.2 relational operators
operator | Operation | example | result |
== | Equal to | 4==3 | FALSE |
!= | Not equal to | 4!=3 | TRUE |
< | less than | 4<3 | FALSE |
> | greater than | 4>3 | TRUE |
<= | Less than or equal to | 4<=3 | FALSE |
>= | Greater than or equal to | 4>=3 | TRUE |
The difference between Java and Scala about = =
Requirement description | Scala code | Java code |
Comparative data | ==Or= | equals() method |
Compare references | eq method | ==Or= |
Example:
val s1 = "abc" val s2 = new String("abc") println(s1 == s2) println(s1.eq(s2))
2.7.3 logical operators
It is used to connect multiple conditions (generally speaking, it is a relational expression), and the final result is also a Boolean value.
Assumption: variable A is true and variable B is false
operator | describe | example |
&& | Logic and | (A & & B) operation result is false |
|| | Logical or | (a | b) the operation result is true |
! | Logical non | ! (A & & B) operation result is true |
be careful:
In Scala code, you cannot continuously negate the value of a Boolean type, but you can do so in Java.
Namely: println(!!true)
This writing will report an error. This writing method is not supported.
2.7.4 assignment operator
Assignment operator is to assign the value of an operation to a specified variable.
operator | describe | example |
= | A simple assignment operator assigns the value of an expression to an lvalue | C = A + B , assign the result of A + B expression to C |
+= | Add and assign | C += A equals C = C + A |
-= | Assign value after subtraction | C -= A equals C = C - A |
*= | Multiply and assign | C *= A equals C = C * A |
/= | Assign value after division | C /= A equals C = C / A |
%= | Assign value after remainder | C% = a equals C = C% a |
<<= | Left shift assignment | C < < 2 equals C = C < < 2 |
>>= | Assignment after shift right | C > > = 2 equals C = C > > 2 |
&= | Bitwise and post assignment | C & = 2 equals C = C & 2 |
^= | Assignment after bitwise XOR | C ^= 2 equals C = C ^ 2 |
|= | Bitwise or post assignment | C |= 2 equals C = C | 2 |
2.7.5 bitwise operators
operator | describe | example |
& | Bitwise and operator | (A & B) output result 12, binary interpretation: 0000 1100 |
| | bitwise or operator | (a | b) output result 61, binary interpretation: 0011 1101 |
^ | bitwise exclusive or operator | (a ^ b) output result 49, binary interpretation: 0011 0001 |
~ | Bitwise negation operator | (~ a) output result - 61, binary interpretation: 1100 0011, in the complement form of a signed binary number. |
<< | Move left operator | A < < 2 output result 240, binary interpretation: 1111 0000 |
>> | Move right operator | A > > 2 output result 15, binary interpretation: 0000 1111 |
>>> | unsigned right shift | A > > > 2 output result 15, binary interpretation: 0000 1111 |
2.8 process control and circulation
2.8.1 if condition judgment
matters needing attention:
- In scala, the if else statement has a return value, which is the last line in the code block
- In scala, the return keyword is not required for return values of methods, functions and condition judgment
- There is no ternary expression in scala. You can use if expression instead of ternary expression
Example:
object Example5 { def main(args: Array[String]): Unit = { val num = 21 val name = if (num > 20) "Xiao Ming" else "Xiao Hong" println("name=>" + name) // If the type of the returned value in the if else statement is different, scala will automatically infer the common type of the two as the variable type //Any val name2 = if (num == 20) "Xiao Ming" else 99 println("name2=>" + name2) println("name2.getClass=>" + name2.getClass) //If the else statement block is missing from the if else {statement, the default is Unit, which is represented by (), similar to void in java val name3 = if (num > 20) "Xiao Ming" val name4 = if (num > 20) "Xiao Ming" else () println(name3) println(name4) } }
2.8.2 for loop
2.8.2.1 simple cycle
Format:
for(i <- expression/array/aggregate){ //Logic code }
Reference code:
object Example7 { def main(args: Array[String]): Unit = { //Using the to method will produce a continuous interval range [0-10], which is contained on both sides for (i <- 0 to 10) { println("i=>" + i) // 0 - 10 } //Using the until method will produce a continuous interval range [0-10], excluding 10 for (i <- 0 until 10) { println("i=>" + i) // 0 - 9 } //Traversal string for (s <- "xiaoming") { println(s) } } }
2.8.2.2 nested loops
Traditional way
for (i <- 1 to 3){ for (j <- 1 to 5) if (j==5) println("*") else print("*") }
Scala specific approach
for (i <- 1 to 3;j <- 1 to 5) if (j==5) println("*") else print("*")
2.8.2.3 guard
if judgment statements can be added to the for loop, which is called guard.
Syntax: for(i <- expression/array/aggregate if expression){ //Logic code }
Reference code:
for (i <- 1 to 10 if (i % 3) == 0) println(i) // i = 3,6,9
2.8.2.4 derivation for loop
In Scala, the for loop has a return value. In the body of the for loop, you can use the yield expression to build a set. The for expression that has used yield is called a derivation.
For each iteration of the for loop, the yield will generate a value, which will be recorded by the loop (in the internal implementation, it is like a buffer). When the loop ends, the set composed of all yield values will be returned, and the type of the returned set is consistent with the type of the traversed set.
For (e < - list (1,2,3)) {yield e * e} / / syntax error. Yield cannot be in any parentheses
Reference code:
var v = for(i <- 1 to 10) yield i * 10 println(v)
2.8.3 while cycle
The use of while and do while in Scala is basically the same as that in Java
2.8.4 break and continue
In Scala, the break and continue keywords similar to Java have been removed, and scala. Com is needed util. breakable and break() methods in Breaks class under control package
2.8.4.1 break usage
Guide Package
import scala.util.control.Breaks._
Wrap expressions with breakable
Add the break() method where you need to exit the loop
Reference code:
import scala.util.control.Breaks._ Breakable{ for (i <- 1 to 10){ if(i == 5) break() else println(i) } }
2.8.4.2 continue usage
The implementation of continue is similar to break, but there are differences. The implementation of break is to wrap the whole expression with Breakable {}, while the implementation of continue is to wrap the loop body of the expression with Breakable {}.
Reference code:
import scala.util.control.Breaks._ for (i <- 1 to 10){ breakable{ if (i % 3 == 0 ) break() else println(i) } }
2.9 methods and functions
Method format:
def Method name (Parameter name: parameter type, parameter name: parameter type) : return type = { //Method body }
The return value type can be omitted (the definition of recursive methods cannot be omitted), which is automatically inferred by the Scala compiler.
If there is a return value type, the return value of the last statement of the method must be consistent with the return value type of the method.
The return value can be left blank. The default value is the value of the {} expression.
Example:
def getMax(a:Int ,b:Int): Int = { if (a>b) a else b }
2.9.1 method parameters
The method parameters in Scala are flexible. It supports the following types of parameters:
1. Default parameters
2. Named parameters
3. Variable length parameters
2.9.1.1 default parameters
Default values can be given to parameters when defining methods.
Reference code:
def getSum1(x:Int = 10 ,y:Int = 20) = { x + y }
2.9.1.2 named parameters
When calling a method, you can specify the name of the parameter to call.
Reference code:
val sum = getSum1(y=1)
2.9.1.3 variable length parameters
If the parameters of a method are not fixed, the parameters of the method can be defined as variable length parameters.
Format:
def Method name (Parameter name: parameter type*) : return type = { //Method body }
2.9.2 method call
2.9.2.1 suffix adjustment usage
Syntax:
Object name.Method name (parameter)
Example:
Math.abs(-1)
2.9.2.2 infix tone usage
Syntax:
Object name method name parameter
Example:
Math abs -1
2.9.2.3 use of curly braces
Syntax:
Object name.Method name{ //Expression 1 //Expression 2 }
Example:
Math.abs{-1}
Method can only use curly braces for one argument
2.9.2.4 usage without parentheses
If the method has no parameters, you can omit the parentheses after the method name
Example:
def say() = println("hello") say
2.9.3 function
Format:
val Variable name = (Parameter name: parameter type, parameter name: parameter type...) =>{ // Function body }
Example:
val f1 = (x:Int,y:Int) =>{ x + y }
2.9.4 difference between method and function
In java, there is no difference between methods and functions, but their names are different. In Scala, functions and methods are different:
1. In Scala, def statement is used to define methods and val statement is used to define functions.
2. In Scala, at runtime, the method is loaded into the method area of the JVM, and the function is loaded into the heap memory of the JVM.
3. The method cannot exist as a separate expression (except for methods with empty parameters), while the function can.
Example:
object Example14 { // Define a parameterized method def m(x:Int) = 2*x // Define a function val f = (x:Int) => 2*x // Define a parameterless method def m1()=1+2 // A parameterized method cannot appear as a final expression m // Functions can appear as final expressions f // Parameterless methods can appear as final expressions m1 }
4. The method can have no parameter list, and the parameter list can also be empty. However, the function must have a parameter list (which can also be empty).
Example:
// Method can have no parameter list def m2 = 100 //Method can have an empty parameter list def m3() = 100 //The function must have a parameter list, otherwise an error is reported var f1 = => 100 //A function can also have an empty argument list var f2 = () => 100
5. Method name means method call; But the function name only represents the function itself.
6. The method can be automatically (called ETA extension) or manually forced into a function; However, functions cannot be converted to methods
Convert method to function:
def m4( x : Int , y : Int ) = { x + y } val f4 = m4 _ println(f4 (1,2))
2.10 classes and objects
A class is an abstraction of an object, and an object is a concrete instance of a class. Classes are abstract and do not occupy memory, while objects are concrete and occupy storage space. Class is a blueprint for creating objects. It is a software template that defines methods and variables included in specific types of objects.
Create classes and objects in short form:
- If the class is empty and has no members, {} can be omitted
- If the constructor parameter is empty, you can omit ()
Example:
object Example15 { class People def main(args: Array[String]): Unit = { val p = new People } }
2.10.1 member variables
You can use var/val to define the member variable, and the object is defined by {object name To access member variables.
Example:
object Example16 { class Person{ var name = "" var age = 0 } def main(args: Array[String]): Unit = { val person = new Person person.name = "Zhang San" person.age = 24 print(s"full name: ${person.name},Age: ${person.age}") } }
Initializing member variables with underscores
When defining member variables of var type, you can use_ Initialize member variables.
String->null Int->0 Boolean->false Double->0.0 ...
Example:
object Example16 { var col1:String = _ var col2:Byte = _ var col3:Int = _ var col4:Long = _ var col5:Float = _ var col6:Double = _ var col7:Char = _ var col8:Boolean = _ }
Member variables of type val must be initialized manually
2.10.2 access modifier
In Scala, there is no public keyword, and members that are not marked as private and protected are public.
The permission modifiers in Scala are only: private, private[this], protected, and default.
Class 2.10.3 constructor
2.10.3.1 main constructor
Syntax:
class Class name(var/val Parameter name:type = Default value,...){ //Construct code block }
explain:
The main constructor is intertwined with the class name. A class can only define one main constructor.
The order in which objects are created must be executed first by the main constructor.
The parameters of the main constructor become the field properties of the class.
In the main constructor parameters, parameters that are not modified by any keywords are private [this] by default
The code not contained in any method is the code of the main constructor.
Reference code:
object Example17 { class Person(var name:String = "Zhang San",var age:Int = 24){ println("The main constructor was called") } def main(args: Array[String]): Unit = { //Empty parameter val p1 = new Person("Li Si",2) //Full reference val p2 = new Person() //Specify parameters val p3 = new Person(age = 2) println(s"p1:${p1.name},${p1.age}") println(s"p2:${p2.name},${p2.age}") println(s"p3:${p3.name},${p3.age}") } }
2.10.3.2 auxiliary constructor
The auxiliary constructor method name defaults to this and cannot be changed. The first line of code of the auxiliary constructor must call the main constructor or other auxiliary constructors. The order of creating objects must be executed first by the main constructor.
Syntax:
def this(Parameter name:Type,...){ //The first line needs to call the main constructor or another constructor //Constructor code }
Example:
object Example18 { class Person { println("The main constructor was called") private var name = "" private var age = 0 def this(name: String){ this() //Call the main constructor println("Auxiliary constructor called-") this.name = name } def this(name: String, age: Int){ this(name) //Call other auxiliary constructors println("Auxiliary constructor called--") this.age = age } } def main(args: Array[String]): Unit = { new Person("zs",20) } }
2.10.4 single case object
There is no static keyword in Scala. If you want to define static variables and static methods similar to those in Java, you need to use the singleton object in Scala. A singleton object means that there is only one object in the world, which is also called an isolated object. Defining a singleton object is very similar to defining a class, that is, replacing class with object.
Its main functions:
1) Tool storage methods and constants
2) Efficiently share a single immutable instance
3) When a single instance is required to coordinate a service
Format:
object Singleton object name{}
The member variables defined in object are similar to static variables in Java. There is only one object in memory.
In the singleton object, the singleton object name can be used directly Call members in the same way.
Example:
object Example19 { object Dog{ val leg_num = 4 def say(): Unit = println("dog") } def main(args: Array[String]): Unit = { println(Dog.leg_num) Dog.say() } }
2.10.5 associated objects
In Java or C + +, classes with both instance methods and static methods are usually used. In Scala, you can achieve the same goal through classes and companion objects with the same name as classes.
definition:
In the same scala class file, if the names of class and object are the same, then class is the associated class of object and object is the associated object of class.
be careful:
- Associated object and associated class names must be the same
- Companion objects and companion classes must be in the same Scala source file
- The associated object and associated class can access the private attribute of each other. If the permission is private[this], it can only be accessed in the current class, and the associated object cannot be accessed directly.
Reference code:
object Example21 { // Associated class class Person{ def eat(): Unit = print("eat" + Person.food) } // Companion Object object Person{ private val food = "meal" } def main(args: Array[String]): Unit = { val person = new Person person.eat() } }
2.10.6 succession
Syntax:
class/object Subclass extends Parent class{ }
Subclass override methods must use the override modifier.
You can override a val field with override, and the var field of the parent class cannot be overridden.
Example:
object Example22 { class Person{ val name = "" var age = 24 def say(): Unit = print("") } class Student extends Person{ override val name = "sjh" override def say(): Unit = print("hello") } def main(args: Array[String]): Unit = { val student = new Student() student.say()//hello } }
2.10.7 abstract classes
Format:
abstract class Abstract class name{ val/var Abstract field name:type def Method name(parameter:Parameter type...):Return type }
Example:
object Example23 { abstract class Shape{ val c:Int def getArea:Double } class Square(x:Int) extends Shape{ override val c: Int = x override def getArea: Double = c * c } class Circle(r:Int) extends Shape{ override val c: Int = r override def getArea: Double = Math.PI * c * c } def main(args: Array[String]): Unit = { val square = new Square(1) println(square.getArea)//1 val circle = new Circle(1) println(circle.getArea)//3.141592653589793 } }
2.10.8 sample class / sample object
2.10.8.1 sample class
Sample class is a special class, which is generally used to save data (similar to Java POJO). It is often used in concurrent programming, Spark, Flink and other frameworks.
Format:
case class Sample class name([var/val] Member variable name 1:Type 1...)
Example:
case class Person(val name:String, var age:Int)
If it is not written, the default modifier of the variable is val, which can be omitted.
If you want to realize that the value of a member variable can be modified, you need to manually add var modification.
Automatically create associated objects and implement some methods in it. The common methods are as follows:
apply() method
You can quickly use the class name to create objects, omitting the new keyword.
toString() method
Each attribute value of the object can be printed directly during printing.
For example: val p = Person()
equals() method
You can use = = directly to compare attribute values.
hashCode() method
The hash value of the same object must be the same, and the hash value of different objects is generally different.
copy() method
It can be used to quickly create instance objects with the same attribute value, and assign values to the specified member variables in the form of named parameters.
unapply() method
Implement the extractor and apply it to pattern matching.
2.10.8.2 sample object
The singleton object decorated with case is called a sample object, and it has no main constructor. It is mainly used in:
- enum
- As a message without any parameters
Example:
object ClassDemo { //Trait Sex, indicating gender trait Sex //Sample object, representing male, inheriting Sex traits case object Male extends Sex //Sample object, representing female, inheriting Sex traits case object Female extends Sex //Define the sample class Person case class Person(var name:String, var sex:Sex){} def main(args: Array[String]): Unit = { val p = Person("sjh", Male) } }
2.11 characteristics
If we need to strengthen the functions of some classes (or objects) without affecting the current inheritance system, we need to put these unique functions into characteristics. The traits in Scala should be decorated with the keyword trait.
characteristic
Characteristics can improve the reusability of code.
Characteristics can improve the scalability and maintainability of code.
Classes and traits are inheritance relationships. Classes and classes only support single inheritance, and classes and traits can inherit single or multiple.
Scala can have common fields, abstract fields, common methods and abstract methods.
If the trait has only abstract content, such trait is called thin interface.
If a trait has both abstract content and concrete content, such a trait is called rich interface.
Syntax:
Defining traits
trait Trait name{ //General field //Abstract field //Common method //Abstract method }
Inherited traits
class Class name extends Trait 1 with Trait 2{ //Override abstract field //Rewrite abstract methods }
Reference code:
object Example25 { trait MsgSender{ def send(msg:String) } trait MsgReceiver{ def receive() } // Class inherits multiple traits class MsgWorker extends MsgSender with MsgReceiver{ override def send(msg: String): Unit = println(s"Send message: $msg") override def receive(): Unit = println("receive messages") } // object inherits trait object MsgWorker extends MsgSender with MsgReceiver{ override def send(msg: String): Unit = println(s"Send message: $msg") override def receive(): Unit = println("receive messages") } def main(args: Array[String]): Unit = { val worker = new MsgWorker worker.send("hello") worker.receive() MsgWorker.send("hello scala") MsgWorker.receive() } }
Mix in object 11.2
Sometimes we want to temporarily enhance or expand the functions of objects without changing the class inheritance system. At this time, we can consider using object blending technology. The so-called object blending technology is that in scala, there is no inheritance relationship between classes and traits, but the class object can have members in the specified traits through specific keywords.
Syntax:
val/var Object name = new class with Idiosyncrasy
Reference code:
object Example26 { trait Logger{ def log(): Unit = println("log..") } class User{ } def main(args: Array[String]): Unit = { // val/var object name = new class val user = new User with Logger user.log() } }
2.11.2 trait construction mechanism
Each trait has only one parameterless constructor, that is, trait also has construction code, but unlike classes, traits cannot have constructor parameters.
When one class inherits another class and multiple trait s, the constructor executes in the following order when creating an instance of this class:
Execute parent constructor
Constructor that executes trait from left to right
If a trait has a parent trait, execute the constructor of the parent trait first
If multiple traits have the same parent trait, the parent trait constructor is initialized only once
Execute subclass constructor
Reference code:
object Example27 { trait A{ println("A") } trait B extends A{ println("B") } trait C extends A{ println("C") } class D{ println("D") } class E extends D with B with C{ println("E") } def main(args: Array[String]): Unit = { new E//DABCE } }
2.12 package
A package is a folder. Decorated with package, you can distinguish between duplicate name classes.
Format:
Format 1: document top marking method-Consolidated Edition Package Package name 1.Package name 2.Package name 3 Format 2: document top marking method-Disassembled version Package Package name 1.Package name 2 Package Package name 3 Format 3: concatenated package statement Package Package name 1.Package name 2{ Package Package name 3{ } }
Scope of package:
Child packages have direct access to the contents of the parent package.
When the upper layer accesses the lower content, it can be realized by importing or writing the full package name.
If the upper and lower layers have the same class, the principle of proximity shall be adopted when using (the lower layer is preferred).
Introduction of package:
scala introduces Java. Net by default Lang package, scala package and Predef package.
The introduction of packages is not limited to the top of Scala files, but can be written wherever needed.
If you need to import all classes and traits in a package, use underscores_ realization.
If multiple imported contain the same class, it can be solved by renaming or hiding.
Rename format:
import java.util.{HashSet => JavaSet}
Hide format:
import java.util.{HashSet => _,_}//Introduce classes other than HashSet under util package
2.13 pattern matching
Pattern matching is a mechanism to check whether a value matches a pattern. A successful matching will deconstruct the matching value into its components at the same time. It is an upgraded version of the switch statement in Java and can also be used to replace a series of if/else statements.
A pattern matching statement includes a value to be matched, a match keyword, and at least one case statement.
Match corresponds to the switch in Java, but it is written after the selector expression. That is: selector match {alternative}.
The match expression completes the calculation by trying each pattern in the order of coding. As long as a matching case is found, the remaining cases will not continue to match.
match..case and switch Case differences
Java writing
switch(n) { case(1): ...; break; case(2): ...; break; default: ...; }
In Scala, you don't need to write break at the end of each time_ Equivalent to default
n match { case "a" | "b" => ... case "c" => ... case _ => ... }
2.13.1 simple pattern matching
Format:
variable match{ case Constant 1 => Expression 1 case Constant 2 => Expression 2 case Constant 3 => Expression 3 case _ => Expression 4 //Default item }
Example:
def main(args: Array[String]): Unit = { println("Enter a word") val word = StdIn.readLine() word 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") } }
2.13.2 type matching
In addition to matching data, matcha expressions can also perform type matching. If we want to execute different logic according to different data types, we can use match expression to implement it.
Format:
Object name match{ case Variable name 1:Type 1 => Expression 1 case Variable name 2:Type 2 => Expression 2 case _:Type 3 => Expression 3 //The expression does not use the variable name. You can use the underscore instead case _ => Expression 4 //Default item }
Example:
def main(args: Array[String]): Unit = { val a:Any = "hadoop" a match { case x:String => println(s"${x}Is a string") case x:Int => println(s"${x}It's a number") case _ => println("Unmatched") } }
2.13.3 guard
Guard refers to adding if condition judgment in case, which can make the code more concise.
Format:
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 //Default item }
Example:
def main(args: Array[String]): Unit = { val a = StdIn.readInt() a match { case x if x > 0 => println("Positive number") case x if x < 0 => println("negative") case _ => println("Is 0") } }
2.13.4 sample class matching
In Scala, pattern matching can be used to match the sample class, so that the member data in the sample class can be obtained quickly.
Format:
Object name match{ case Sample type 1(Field 1, Field 2..) => Expression 1 case Sample type 2(Field 1, Field 2..) => Expression 2 case Sample type 3(Field 1, Field 2..) => Expression 3 case _ => Expression 4 //Default item }
Example:
object ClassDemo { case class Customer(name:String, age:Int) case class Order(id:Int) def main(args: Array[String]): Unit = { val a:Any = Customer("sjh", 20) a match { case Customer => println("yes customer") case Order => println("yes order") case _ => println("Unmatched") } } }
2.13.5 set matching
Matching array example
def main(args: Array[String]): Unit = { //Define three arrays val arr1 = Array(1, 2, 3) val arr2 = Array(0) val arr3 = Array(0 , 1, 2, 3,4) arr1 match { case Array(1, _, _) => println("The length is 3 and the first element is 1") case Array(0) => println("Length 1, element 0") case Array(0, _*) => println("First element 0, any other element") } }
Match list example
def main(args: Array[String]): Unit = { //Define three lists val list1 = List(1, 2, 3) val list2 = List(0) val list3 = List(0, 1, 2, 3,4) list3 match { case List(1, _, _) => println("The length is 3 and the first element is 1") case List(0) => println("Length 1, element 0") case List(0, _*) => println("First element 0, any other element") case List(x, y) => println(s"Match list: a list containing only two arbitrary elements,The element is: ${x},${y}") } //Equivalent to list2 match { case 1 :: _ :: _ ::Nil => println("The length is 3 and the first element is 1") case 0 :: Nil => println("Length 1, element 0") case 0 :: _ => println("First element 0, any other element") case x :: y :: Nil => println(s"Match list: a list containing only two arbitrary elements,The element is: ${x},${y}") } }
Matching tuple example
def main(args: Array[String]): Unit = { //Define three tuples val a = (1, 2, 3) val b = (3, 4, 5) val c = (3, 4) a match { case (1, _, _) => println("The length is 3 and the first element is 1") case (_, _, 5) => println("The length is 3 and the tail element is 5") case _ => println("Mismatch") } }
2.14 higher order function
Scala combines object-oriented and functional features. If a function's parameter list can receive function objects, then the function is called a high-order function.
2.14.1 function as value
Function objects can be passed to methods.
Example: convert each element in an integer list to the corresponding number of *.
def main(args: Array[String]): Unit = { val list = (1 to 5).toList val func = (x:Int) => "*" * x val list1 = list.map(func) println(list1)//List(*, **, ***, ****, *****) }
2.14.2 anonymous functions
Functions that are not assigned to variables are anonymous functions
Example:
def main(args: Array[String]): Unit = { val list = (1 to 5).toList val list1 = list.map((x:Int) => "*" * x) val list2 = list.map("*" * _) println(list1)//List(*, **, ***, ****, *****) println(list2)//List(*, **, ***, ****, *****) }
2.14.3 coritization
Corrilization refers to the process of converting a method that originally received multiple parameters into multiple methods with only one parameter list
Example: define a method to splice two strings
object ClassDemo { //Common writing def merge1(str1:String, str2:String): String = str1 + str2 //Coriolis f1 representation function def merge2(str1:String, str2:String)(f1:(String, String) => String): String = f1(str1, str2) def main(args: Array[String]): Unit = { println(merge1("abc", "def"))//abcdef println(merge2("abc", "def")(_ + _))//abcdef } }
2.14.4 closure
A closure is a function that can access data that is not in the current scope. (coritization is a closure)
Example: get the sum of two integers through closure
def main(args: Array[String]): Unit = { val x = 10 val sum = (y:Int) => x + y println(sum(10))//20 }
2.14.5 control abstraction
Assuming that the parameter list of function A needs to receive A function B, and function B has neither input value nor return value, then function A is called control abstract function.
Example:
object ClassDemo { val func = (f1:() => Unit) => { println("welcome") f1() println("bye") } def main(args: Array[String]): Unit = { func(() => println("shopping..")) } }
2.15 generics
2.15.1 generics
Generic refers to a specific data type. In Scala, generic is represented by [data type].
generic method
Example, define a generic method to obtain intermediate elements of any data type
def getMiddleElement[T](array: Array[T]): T = {array(array.length / 2)}
Generic class
For example, a Pair generic class is defined, which contains two fields and the field type is not fixed
class Pair[T](var a:T, var b:T)
Generic trait
trait Logger[T]{ val a:T def show(b:T) } object ConsoleLogger extends Logger[String]{ override val a: String = "sjh" override def show(b: String): Unit = println(b) }
2.15.2 upper and lower bounds
upper bound
Use T <: type name to add an upper bound to the type, indicating that the type must be t or a subclass of T.
object ClassDemo { class Person class Student extends Person def demo[T <: Person](array: Array[T]): Unit = println(array) def main(args: Array[String]): Unit = { demo(Array(new Person)) demo(Array(new Student)) demo(Array("a"))//report errors } }
Lower bound
Use t >: type name means to add a lower bound to the type, indicating that the type must be a parent of T or t.
If a generic has both an upper bound and a lower bound, the lower bound is written in front, [t >: a <: b]
2.15.3 covariant, inverter and non transformer
Covariance: there is a parent-child relationship between Class A and class B, and there is also a parent-child relationship between Pair[A] and Pari[B].
class Pair[+T]{}
Inversion: Class A and class B have a parent-child relationship, but Pair[A] and Pari[B] have a child parent relationship.
class Pair[-T]{}
Non variable: Class A and class B are parent-child relationships, and there is no relationship between Pair[A] and Pari[B].
class Pair[T]{} //The default type is immutable
Example:
object ClassDemo { class Super class Sub extends Super class Temp1[T] class Temp2[+T] class Temp3[-T] def main(args: Array[String]): Unit = { //Test non variable val t1:Temp1[Sub] = new Temp1[Sub] //val t2:Temp1[Super] = t1 error //Test covariance val t3:Temp2[Sub] = new Temp2[Sub] val t4:Temp2[Super] = t3 //Test inverter val t5:Temp3[Super] = new Temp3[Super] val t6:Temp3[Sub] = t5 } }
2.16 assembly
Classification:
Mutable collection thread unsafe
The set itself can change dynamically, and the variable set provides methods to change the elements in the set.
scala.collection.mutable / / manual package import is required
Immutable collection thread safety
The default class library. Once the initialization of the elements in the collection is completed, they cannot be changed. Any change to the collection will generate a new collection.
scala.collection.immutable / / manual package import is not required
Set is unordered and unique
·HashSet
·SortedSet
·TreeSet
·BitSet
·ListSet
Seq sequence, ordered, repeatable, element indexed
High efficiency index sequence
· enhancement of numericrange
· Range ordered integer sequence, similar to arithmetic sequence
· Vector general immutable data structure, which takes a long time to obtain elements and updates randomly faster than arrays or lists
· String string
· LinearSeq linear sequence, which mainly operates the first and last elements
· List
· Queue queue
· Stack stack immutable Stack has been deprecated
· Stream
Map
·HashMap
·SortedMap
·TreeMap
·ListMap
Variable sets are richer than immutable sets. For example, in Seq, Buffer sets are added, such as ArrayBuffer and ListBuffer.
2.16.1 Traverable
Traverable is a trait whose sub trait is immutable Traverable and mutable Traverable is the parent trait of immutable set and variable set respectively.
Format:
Create an empty traversable object.
val t = Traverable.empty[Int] val t = Traverable[Int]() val t = Nil
Create a traversable object with parameters.
val t = List(1, 2, 3).toTraverable val t = Traverable(1, 2, 3)//Generate List by default
Transpose:
Use the transfer method.
The transpose operation requires the same number of elements in each set.
def main(args: Array[String]): Unit = { val t1 = Traversable(Traversable(1, 4, 7), Traversable(2, 5, 8), Traversable(3, 6, 9)) println(t1)//List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9)) val transpose = t1.transpose println(transpose)//List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) }
Splicing:
++Data can be spliced, but a large number of temporary collections will be created, which can be realized through concat method.
def main(args: Array[String]): Unit = { val t1 = Traversable(1, 2, 3) val t2 = Traversable(4, 5, 6) val traversable = Traversable.concat(t1, t2) println(traversable)//List(1, 2, 3, 4, 5, 6) }
Filter:
Use the collect method to realize the partial function, which is used in combination with the set to filter the specified data from the set.
def main(args: Array[String]): Unit = { val t1 = (1 to 10).toList def filter:PartialFunction[Int, Int] = { case x if x % 2 == 0 => x } //val t2 = t1.collect(filter) val t2 = t1.collect({ case x if x % 2 == 0 => x }) println(t2)//List(2, 4, 6, 8, 10) }
scan method
def scan[B](z:B)(op: (B, B) => B)
[B] Represents the data type of the return value, (z:B) represents the initialization value, (OP: (B, b) = > b) represents the specific function operation.
Example: define a traversable set, store 1-5, assume the initial value is 1, and obtain the factorial value of each element respectively.
def main(args: Array[String]): Unit = { val t1 = 1 to 5 //val seq = t1.scan(1)((a, b) => a * b) val seq = t1.scan(1)(_ * _) println(seq)//Vector(1, 1, 2, 6, 24, 120) }
Gets the specified element of the collection
head/last: get the first / last element without throwing an exception
headOption/lastOption: get the first / last element, and the return value is Option
Find: find the first element of the symbol condition
slice: intercept some elements in the collection, close left and open right
def main(args: Array[String]): Unit = { val t1 = 1 to 5 println(t1.head)//1 println(t1.last)//5 println(t1.headOption)//Some(1) println(t1.lastOption)//Some(5) println(t1.find(_ % 2 == 0))//Some(2) println(t1.slice(0, 2))//Vector(1, 2) }
Judge whether the element is legal
forall returns true if all elements in the collection meet the conditions
exist returns true if an element in the collection meets the condition
def main(args: Array[String]): Unit = { val t1 = 1 to 5 println(t1.forall(_ % 2 == 0))//false println(t1.exists(_ % 2 == 0))//true }
Aggregate function
count counts the number of qualified elements in the collection
sum get collection elements and
product gets the scores of all elements in the collection
max gets the maximum value of all elements in the collection
min gets the minimum value of all elements in the set
Collection type conversion
toList
toSet
toArray
toSeq
Fill element
fill quickly generates a specified number of elements
The iterator generates a specified number of elements according to the specified conditions
range generates all the data of the specified interval in a certain interval. The interval parameter is 1 by default
def main(args: Array[String]): Unit = { val t1 = Traversable.fill(5)("a") println(t1)//List(a, a, a, a, a) val t2 = Traversable.fill(2, 2, 2)("a") println(t2)//List(List(List(a, a), List(a, a)), List(List(a, a), List(a, a))) val t3 = Traversable.iterate(1, 5)(_ * 10) println(t3)//List(1, 10, 100, 1000, 10000) val t4 = Traversable.range(1, 100, 7) println(t4)//List(1, 8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99) }
Iterable
Iteratable represents a set that can be iterated. It inherits the Travsersable trait and is also the parent trait of other sets. It defines the method of obtaining iterators, which is an abstract method.
Example of traversing a collection:
def main(args: Array[String]): Unit = { val list = List(1, 2, 3, 4, 5) //Mode 1: active iteration val iterator = list.iterator while (iterator.hasNext) print(iterator.next() + " ") //Mode 2 passive iteration list.foreach(x => print(x + " ")) }
Group traversal example:
def main(args: Array[String]): Unit = { val i = (1 to 5).toIterable val iterator = i.grouped(2) while (iterator.hasNext) print(iterator.next() +" ")//Vector(1, 2) Vector(3, 4) Vector(5) }
Generate tuples by index:
def main(args: Array[String]): Unit = { val i = Iterable("A", "B", "C", "D", "E") val tuples = i.zipWithIndex.map(x => x._2 -> x._1) println(tuples)//List((0,A), (1,B), (2,C), (3,D), (4,E)) }
Judge whether the set is the same:
def main(args: Array[String]): Unit = { val i1 = Iterable("A", "B", "C") val i2 = Iterable("A", "C", "B") val i3 = Iterable("A", "B", "C") println(i1.sameElements(i2))//false println(i1.sameElements(i3))//true }
2.16.2 Seq
Seq trait represents the sequence of elements arranged in a certain order. Sequence is a special iterative set, which is characterized by order, repeatability and index
To create a Seq set:
def main(args: Array[String]): Unit = { val seq = (1 to 5).toSeq println(seq)//Range(1, 2, 3, 4, 5) }
Get length and element:
Get the length through the length or size method, and get the element directly through the index.
def main(args: Array[String]): Unit = { val seq = (1 to 5).toSeq println(seq.length)//5 println(seq.size)//5 println(seq(0))//1 }
Gets the index value of the specified element
indexOf gets the first occurrence position of the specified element in the list
lastIndexOf gets the position of the last occurrence of the specified element in the list
indexWhere gets the element that meets the condition and the index that appears for the first time in the collection
lastIndexWhere gets the element that meets the condition and the index of the last occurrence in the collection
indexOfSlice gets the first occurrence position of the specified subsequence in the collection
Cannot find return - 1.
Determine whether the specified data is included:
Does startsWith begin with a reference to the stator sequence
Whether endsWith ends with a reference sequence
contains determines whether a specified data is included
containsSlice determines whether a specified subsequence is included
Modify the specified element:
updated modifies the element of the specified index position to the specified value.
patch modifies the element of the specified interval to the specified value.
def main(args: Array[String]): Unit = { val seq = (1 to 5).toSeq val seq1 = seq.updated(0, 5) println(seq1)//Vector(5, 2, 3, 4, 5) //Parameter 1 initial index parameter 2 replaced element parameter 3 replaced several val seq2 = seq.patch(1, Seq(1, 2), 3) println(seq2)//Vector(1, 1, 2, 4, 5) }
2.16.3 Stack
Top get stack top element
push stack
pop out of stack
Clear clear all elements
mutable.Stack has a unique method pushAll, which pushes multiple elements into the stack.
ArrayStack has a unique method: dup, copy the top element of the stack. preseving, execute the expression, and restore the stack after execution.
Example:
def main(args: Array[String]): Unit = { //Stack from right to left val s = mutable.Stack(1, 2, 3, 4, 5) println(s.top)//1 println(s.push(6))//Stack(6, 1, 2, 3, 4, 5) println(s.pushAll(Seq(7, 8, 9)))//Stack(9, 8, 7, 6, 1, 2, 3, 4, 5) println(s.pop())//9 println(s.clear())//() }
Example: define variable stack storage 1-5, copy the top elements of the stack through dup method, and empty the elements first and then restore through preseving method.
def main(args: Array[String]): Unit = { //Stack from right to left val s = mutable.ArrayStack(1, 2, 3, 4, 5) //Copy stack top element s.dup() println(s)//ArrayStack(1, 1, 2, 3, 4, 5) s.preserving({ //After this method is executed, the data in the stack will be recovered s.clear() }) println(s)//ArrayStack(1, 1, 2, 3, 4, 5) }
2.16.4 Queue
Represents a queue, which is characterized by FIFO. The commonly used queue is mutable Queue, which is internally implemented by MutableList.
enqueue join
dequeue out
dequeueAll removes all elements that meet the criteria
dequeueFirst removes the first element that satisfies the condition
3. Actor model
Introduction to Actor
The Actor concurrent programming model in Scala can be used to develop concurrent programs that are more efficient than Java threads.
Problems of Java Concurrent Programming
In Java Concurrent Programming, each object has a logic monitor, which can be used to control the multi-threaded access of the object. We add the synchronized keyword to mark that synchronous lock access is required. The locking mechanism ensures that only one thread accesses the shared data at the same time. However, there are resource competition and deadlock problems in this way. The larger the program, the more troublesome the problem is.
Resource competition
thread deadlock
Actor concurrent programming model
The concurrent programming model provided by Scala is not the same as the concurrent programming model provided by Scala. Actor concurrent programming model is a concurrent programming mode that does not share data and relies on message transmission, which can effectively avoid resource contention, deadlock and so on.