Scala basic syntax

Posted by Sphen001 on Wed, 12 Jan 2022 20:01:36 +0100

Scala is a multi paradigm programming language. This tutorial focuses on functional programming

This tutorial is suitable for people who have mastered the Java programming language

Constants and variables

var can be used to declare a variable:

var var_name[:type] = xxx

Among them, the type declaration of the attribute can be omitted Then scala will automatically guess the type of attribute Even if the type can be omitted, scala is different from python

Scala officials do not recommend defining too many variables. It is best not to define any variables (the effects of all variables are completed through functions)

val can be used to declare a constant:

val val_name[:type] = xxx

Constants cannot be modified

Basic type

Scala provides the following basic data types:

type explain
Byte Byte type
Short Short
Int integer
Long Long integer
Char character
String character string
Float float
Double Double precision
Boolean Boolean

In addition to String, it is located in Java Lang, the other basic types are under the package of scala Scala doesn't have the concept of all real basic types. In fact, they are all encapsulated classes However, these basic types can be assigned directly in scala (new is not required)

scala and Java Lang packages are automatically introduced by scala, so using these classes does not require any declaration

For example:

val flag = true
// Equivalent to
val flag: Boolean = true

In Scala, String supports three quotation marks "" "xxx" "" this supports native strings. Strings in three quotation marks will be directly treated as native strings without any escape

Scala provides a rich wrapper class RichXxx for basic types And can realize automatic conversion


In Scala, an operator is a method, and a method is an operator There are no real operators in scala. Operators can actually be called through functions:

// The following two expressions are the same:
val num1 = 2 + 3
val num2 = 2.+(3)

Literal 2 exists as an object, and there is a + method in the object

For a method, you can use the operator's method to call:

// The following two expressions are the same:
val str1 = "123456".charAt(1)
val str2 = "123456" charAt 1

Scala has no real operators. All operators will be converted into method calls

If the method receives more than one parameter, the bracket cannot be omitted. If there is no parameter, the point and bracket can be omitted:

val str1 = "123456".substring(2, 3)
val str2 = "123456" substring (2, 3)
val str3 = "a".toUpperCase()
val str4 = "a" toUpperCase

Methods in Scala have priority It is reflected as the priority of the operator in the expression For a series of method calls, the method with higher priority will be called first

The priority is determined according to the method name and the first character of the method name. The higher the following characters are, the higher the priority is:

  1. * / %
  2. + -
  3. :
  4. = !
  5. <>
  6. &
  7. ^
  8. |
  9. All letters
  10. All assignment operators

The priority can be changed through parentheses. Methods with the same priority are called from left to right

Operators fall into three categories:

  • Infix operator between two operands
  • Suffix operator, which follows a unique operand
  • Prefix operator. The operator is in front of a unique operand. Scala only provides four kinds: -, +, ~,% The prefix operator will be translated as "unary_x". For example, "- 3" will be translated as "3.unary_ - ()". We cannot define the prefix operator ourselves

The special method ending with ":" character is called by the right operand and passed in the left operand For example, "a::b" will be translated as "(b).::(a)"

Built in control structure

If can be used as judgment, and its usage is basically the same as java However, if in scala has a return value. If will return the value of the last expression after execution, for example:

val num = 10

val res = if (num > 100) {
    "num Greater than 100"
else if (num < 100 && num > 5) {
    "num Between 5 and 100"
else {
    "num Less than 5"


The result of res should be "num between 5 and 100" if is actually a function. It does not print in the function, which meets the concept of functional programming

While and do While can be used for loops, just like java The return value of while in scala is Unit, which means there is no return value While requires variables and may have additional effects, which is not in line with the idea of functional programming. Therefore, the official does not recommend using while to write loops, but recursive replacement

For example, use recursion to implement calculations from 1 to 100:

def sum100(x: Int, sum: Int): Int = {
    if (x <= 100) {
        sum100(x + 1, sum + x)
    else {

val res = sum100(1, 0)

All loop controls should be written in such a recursive form

The use of for is similar to that of java You can use for to traverse the collection:

val list = List(1, 3, 4, 5, 12)
for (x:Int <- list) {

The to operator is used to generate a range of arrays and can be directly used for loops in a certain range:

for (x <- 1 to 5) {

for can also implement filtering. for example, you can traverse the even number of 0-100 through the following code:

for (x <- 0 to 100; if x % 2 == 0) {

Use multiple ';' You can filter multiple conditions:

for (x <- 0 to 100; if x > 20; if x < 80) {

Nested loops can be implemented using for

for (i <- 1 to 9; j <- 1 to i) {
    print(i * j + ",")

This prints the results of all multiplications within 10

for also supports variable definition between streams, and can define a shared variable in multiple loops Inter stream variables support if assignment. for example, print a complete 99 multiplication table through the following code:

for (i <- 1 to 9; j <- 1 to i; next = if (i == j) "\n" else "\t") {
    print(i + "*" + j + "=" + i * j + next)

The return value of for is also Unit But yield allows for to assemble the last return value of each loop into a collection So the above code can be converted to:

val res = for (i <- 1 to 9; j <- 1 to i; next = if (i == j) "\n" else "\t") yield {
    i + "*" + j + "=" + i * j + next


This meets the requirements of functional programming

scala inherits the exception mechanism of java. You can throw an exception through the throw keyword and try catch... Finally, exceptions can be caught

catch is written differently from java, as follows:

try {
} catch {
    case e: Exception1 => ...
    case e: Exception2 => ...
} finally {

try can have a return value For example:

val res = try {
    "no exception"
} catch {
    case e: Exception => "have an exception"


Note that if it is returned in finally, the return value will not affect the return values of try and catch, which is different from java (java will return the return value of finally anyway)

match ... case is similar to java switch case. Here is an example:

val str = "abc"
val res = str match {
    case "abc" => "I am abc"
    case "bbb" => "I am bbb"
    case _ => "I am neither abc Neither bbb"


There is no need to write break, "_" Represents any data

Continue and break are not present in scala If you want to jump out or continue the loop, you can use recursive implementation


Scala supports functional programming, and function is the most important concept in scala

A function is a collection of code with specific functions, which is composed of function modifier, function name, parameter list, return value declaration and function body

[private | protected] [override] [final] def fun_name(param: type[,param: type]...) [:retType] = {

Permission can control the callable domain of a function. The default is public Override and final are concepts used in OOP

The return value type can be omitted and automatically inferred by scala

If the function body has only one line, the curly braces of the function body can be omitted

If you return a value in the function body without using the return keyword, the return of the last statement is used as the return value of the function by default

Unit means no return value. If a function declaration has no return value declaration and there is no "=" in front of the function body, the return value is unit by default

Functions can be declared by direct quantity. The syntax is: (parameter list) = > {function body} If the function has only one line, curly braces can be omitted

If there is only one parameter and there is no ambiguity, the parentheses of the parameter list can not be written

The declaration method of function direct quantity has no method name and cannot be called directly This definition is mainly used for function values and higher-order functions

Function is a first-class citizen of scala and has complete functions:

  • Become a member of a class
  • Assign to a variable
  • Pass it as an argument to another function
  • Returns another function from one function

Function as a member of a class

Like java, a function can be used as a member of a custom class to describe some behavior of the class

class Person {

  def eat(food: String): Unit = {
    println("eating " + food)


object Main {
  def main(args: Array[String]): Unit = {
    val p = new Person()"Apple")

Function assigned to a variable

A function can be assigned to a variable (including a constant) like a general value This function can then be called through a variable

val add = (x: Int, y: Int) => x + y
println(add(1, 2))

Direct variables are usually used when assigning values to a variable

Defining methods in methods can achieve similar results:

object Hello {
  def main(args: Array[String]): Unit = {
    val test = new Test

class Test {
  def foo(): String = {
    def hello(): String = {
      "hello, world"


We can even define a function first and then assign it to a variable, which requires writing "" in the parameter Indicates that the parameters are specified at the time of subsequent calls:

object Hello {

  def sum(x: Int, y: Int, z: Int): Int = {
    x + y + z

  def main(args: Array[String]): Unit = {
    val sumFun = sum(_, _, _)
    println(sumFun(1, 2, 3))

"val sumFun = sum(_, _, _)" It can be simplified to "val sumfun = sum"

When defining function variables, you can specify some determined parameters first, and use "_" for undetermined parameters:

object Hello {

  def sum(x: Int, y: Int, z: Int): Int = {
    x + y + z

  def main(args: Array[String]): Unit = {
    val sumFun = sum(_: Int, _: Int, 6)
    println(sumFun(2, 4))

Use "" Some very flexible function calls can be implemented

Higher order function

Higher order functions are functions that can be passed as arguments to or returned from another function Super flexible programming can be realized by using high-order functions This is similar to the function pointer of C language, but it is safer

Let's first look at using a function as a parameter, which requires a clear declaration of the return value and parameters of the function, which is defined by "(paramtypes) = > (ReturnType)". For the contents in parentheses, you only need to write the type of the parameter. The following is a simple example:

def operate2Int(x: Int, y: Int,
                opera: (Int, Int) => Int): Int = {
    opera(x, y)

val add = (x: Int, y: Int) => x + y

println(operate2Int(5, 1, add))

If you want to return a function, you also need to fully declare the style of the returned function when declaring the return value type:

def opt2NumFun(funName: String): (Int, Int)=>Int = {
    funName match {
        case "add" => (x, y) => x + y
        case "sub" => (x, y) => x - y
        case "mul" => (x, y) => x * y
        case "div" => (x, y) => x / y
        case _ => (_, _) => 0

println(opt2NumFun("add")(5, 1))
println(opt2NumFun("sub")(10, 5))
println(opt2NumFun("mul")(3, 10))
println(opt2NumFun("div")(30, 3))

The parameter type can be omitted when returning, because the structure of the return function has been declared at the time of definition The type of parameter can be inferred automatically

When returning a function, there is a simpler way to write it If the parameters of the function body call of the function you return are called in sequence and each parameter is used only once, you can omit the parameter list declaration and change all parameters to ""

The above opt2NumFun can be simplified to:

def opt2NumFun(funName: String): (Int, Int)=>Int = {
    funName match {
        case "add" => _ + _
        case "sub" => _ - _
        case "mul" => _ * _
        case "div" => _ / _
        case _ => (_, _) => 0


A lot has been covered before using the placeholder "" As an example, let's make a simple summary

You can use "" in the function direct quantity Use as one or more parameters so that you no longer have to declare a function's parameter list

For example, the add function can be simplified to:

val add = (_:Int) + (_:Int)
println(add(10, 1))

add is still a function, but the parameter list and return value do not need to be declared The premise of using this method is that all parameters of the function are used once and in strict order of declaration

"_" If the type can be inferred, the type declaration can be omitted, otherwise the type must be declared

For example, the following situation can automatically infer "" Type of:

def opt3Num(func: (Int, Int, Int) => Int,
            x: Int, y: Int, z: Int): Int = {
  func(x, y, z)

println(opt3Num(_ + _ + _, 1, 3, 4))
println(opt3Num(_ + _ * _, 1, 2, 5))
println(opt3Num(_ / _ / _, 30, 10, 3))

The above code can be further simplified:

val opt3Num = (_:(Int, Int, Int)=>Int)(_: Int, _: Int, _: Int)
println(opt3Num(_ + _ + _, 1, 3, 4))
println(opt3Num(_ + _ * _, 1, 2, 5))
println(opt3Num(_ / _ / _, 30, 10, 3))

Placeholders can also replace all or part of the parameter list when passing a function to a variable This has been demonstrated before. I won't demonstrate it again


Closure is an important concept Programming languages with high - order functions generally have closure

If an external variable is used in the definition of a function Because it is a variable, the value of this variable is uncertain when calling the function If an external variable is used when calling a function, the value of the variable is brought into the function to become the internal value of the function. This process is called closure

Closures can cause some problems Because a function uses closures to get the value of an external variable only when it needs an external variable However, the external variable may change at any time during the function call. In this way, if the function uses the external variable once and uses it again after a while, the value of the external variable used in the two times may be different

Similarly, closures may change the value of external variables, which may also change the use of this variable by other functions, resulting in undefined behavior

Moreover, because functions may hold references to external variables, external variables may not be released by GC, which may lead to memory leakage

In development, we should try to avoid the harm caused by closures For example, when referring to external data inside a function, you should try to refer to constants instead of variables

Variable parameters

In scala, you can make the last parameter repeatable, so that the parameters of the function can be changed The writing method is to add an "*" after the parameter

def add(nums: Int*): Int = {
    var sum = 0
    for (num <- nums) {
        sum += num

println(add(1, 2, 3))
println(add(4, 5, 6, 7, 8))

Variable parameters are treated as arrays

Tail recursion

In Scala, you should try to use recursion to replace loops But the efficiency of recursion is not high

If a recursive call occurs only in the last expression of a function, scala can optimize the recursion Because this recursive call does not need to use the result of the last call, it can be transformed into a simple iteration at the bottom without pressing the stack

For example, calculate the sum of even numbers from 1 to 100, and if it is greater than 100, the call ends, which can be optimized into a tail recursion:

def foo(x: Int, sum: Int): Int = {
    if (sum > 100 || x > 100) {
    else if (x % 2 == 0) {
        foo(x + 1, sum)
    else {
        foo(x + 1, sum + x)
println(foo(1, 0))

Because every recursion occurs in the last statement of the function, this is a tail recursion

Custom control structure

scala uses high - order functions and Coriolis to implement custom control structures

Higher order functions are described above Coriolism is the process of splitting the parameter list of a function into multiple parameter lists

Here is a simple "add and print" function:

def addAndPrint(num1: Int, num2: Int, pf: (Int)=>Unit): Unit = {
    val sum = num1 + num2
addAndPrint(5, 7, println)

We can actually split addAndPrint Because we found that the parameter list of this function consists of two types: one is two numbers for increasing; The other is a print function:

def addAndPrint(num1: Int, num2: Int)(pf: (Int)=>Unit): Unit = {
    val sum = num1 + num2

addAndPrint(5, 7)(println)

The parameter list of addAndPrint becomes two When calling, you also need to pass two parameters

When high - order functions and Coriolis are used together, a custom control structure can be constructed After coritization of a function, if a parameter has only one value to pass, you can rewrite the parentheses into curly braces

For example, addAndPrint above can be called as follows:

addAndPrint(10, 12) {

It's like a control structure In fact, the essence is the call of a higher-order function

The foreach of List is a custom controller that allows us to do some behavior for each number of a List For example, the following code will print each element of the List after adding 10:

val li = List(1, 3, 5, 10)

li.foreach {
    (num: Int)=> {
        println(num + 10)

The above code can be simplified to:

val li = List(1, 3, 5, 10)

li.foreach {


scala is a multi paradigm programming language, so in addition to functional programming, scala also supports OOP

The definition of scala class is similar to that of java Class can declare classes, which can contain properties and methods, and instantiate objects through new All members and methods are public by default. The permissions can be changed by using private and protected Scala does not have default permission

scala cannot define static members Because scala believes that static members will destroy the encapsulation of OOP Static members are separated from the object level and are the product of procedural programming. Moreover, if multiple threads seize a static member, it will bring thread safety problems Static members will always occupy memory and will never be released by GC

If you need static functions in scala, you can use singleton objects to implement them

Singleton object

Using object, you define a singleton object The method of using singleton object does not need to create object, but uses singleton object point method call The effect is like a static member

Scala will automatically help us instantiate the singleton and ensure that it is globally unique. We can call the methods of the singleton without specifying new

Singleton objects can exist alone or bound to a class When a singleton object and a class are written in the same file with the same name, they are bound to each other A singleton object is a companion object of a class The two can access each other's private members

When we call a method in a singleton object, we do not need to instantiate, but when we call a method in a class, we must instantiate the object

For example:

class Person {
  def eat(): Unit = {
    println("Have a meal")

object Person {
  def sleep(): Unit = {
    println("Sleep sleep")

If we want to call the sleep() method, we can call it directly, but the eat() method must be instantiated and then called:

val p = new Person

The above implements a function similar to static

The entry program must be written in a singleton object The singleton object is stored in a special predef package This package will be imported automatically by scala Therefore, we use singleton objects without additional import packages


The format of classes defined in scala is as follows:

class class_name [(construct_list)] {

Construction parameters can be omitted. If there is no class body, curly braces can be omitted

Unlike java, the constructor is placed after the class name, and the constructor body is written directly in the class body Places that are neither properties nor methods are automatically interpreted as constructor bodies

The variables in the construction parameter list will be automatically added to the properties of the class. We don't need to write "" like java These properties are private by default

Here is a simple demonstration:

object Test {
  def main(args: Array[String]): Unit = {
    val p = new Person("zhang", 20)

class Person (name: String, age: Int) {

  println("construct a person")

  def show(): Unit = {
    println("name = " + name + ",age = " + age)

The output of this code is:

construct a person
name = zhang,age = 20

If you want to provide multiple constructors, you need to define an auxiliary constructor, which is defined separately Defined as "def this()" The first action of each auxiliary constructor in scala is always to call other constructors, either the main constructor or other auxiliary constructors

That is, the main constructor will be called anyway

object Test {
  def main(args: Array[String]): Unit = {
    val p1 = new Person()
    val p2 = new Person("zhang")

class Person (name: String, age: Int) {

  def this() {
    this("default", 0)
    println("call this()")

  def this(name: String) {
    this(name, 0)
    println("call this(String)")

  println("construct a person")

Code output:

construct a person
call this()
construct a person
call this(String)

Override and reload

scala supports overriding, that is, overriding the method of the parent class. You only need to add override in front of the method definition This syntax is similar to C #

If the method does not add override, an error will be reported For example:

class Fruit {
  def eat(): Unit = {
    println("eat fruit")

class Apple extends Fruit {
  override def eat(): Unit = {
    println("Eat apples")

We can override the toString method as a matter of course:

object Test {
  def main(args: Array[String]): Unit = {
    val apple = new Apple

class Apple {
  override def toString: String = "A little apple"

The usage of overloading is similar to java. You can define multiple methods with the same name, which will not be demonstrated here

Nonparametric method

In scala, parameterless methods are a bit special A parameterless method can actually be an attribute, and an attribute can also be a parameterless method

object Test {
  def main(args: Array[String]): Unit = {
    val p = new Person


class Person {
  def say1 = "LOL"

  // The above wording is the same as the following
  def say2(): String = {

  // Same as below
  val say3 = "LOL"

If a method is parameterless, it is the same as a general attribute to the outside So LOL is printed three times. In fact, in scala, attributes also exist as functions The above say3 will actually be converted to say1

This also proves that in scala, everything is a function

If you omit parentheses when defining a parameterless function, you cannot omit parentheses when calling If omitted, you can omit the parentheses

The following strategy is generally used to decide whether to add parentheses to the parameterless method:

  • If the method is closed and has no external impact, it is best to omit the parentheses In this way, external callers can treat it as an attribute to simplify the programming model
  • If the method is not closed and has an impact on the outside, such as reading files, it is best to add parentheses If you don't add it, it will make people wonder: just using an attribute leads to the change of the external environment


Similar to java,scala allows classes to be stored separately to realize the function of distinguishing namespaces Like java, you can use the package keyword to specify the package where the current code is located

However, the package of scala has nothing to do with the actual storage location of classes, so the concept of package here is actually different from that of java, which is very similar to that of C + + and c#'s namespace But the compiled class file will really be stored in the package folder

Then, like C + + and c#, scala allows multiple packages to be declared in the same file:

package cn {
    package lazycat {
        // The package here is CN lazycat

    package hi {
        // The package here is CN hi

However, it is generally not recommended to write this, which will lead to very chaotic package management It is also recommended to declare only one package in a file

To import a package, use import Unlike java, import can appear anywhere in the code (java only allows import to appear in front of the code)

If you want to reference everything under a package, use "import xx.xx." All right We can even use an import to batch import some packages:

import java.util.{List, Map}

This is more convenient than java. java needs to write multiple imports to complete the import of multiple members

We can even alias some imported classes:

import java.util.{SimpleDataFormat => Sdf}

In this way, when instantiating this class object below, you can replace it with an alias:

val s: Sdf = null

Additional access rights

In addition to public, private and protected, Scala provides more detailed permission control. We can add a bracket after the permission statement and add some additional package names allowed to access (much like friends in C + +), for example:

private [cn.hhh] val f: String

So on CN HHH package, even if it is not in this class, you can directly access the f attribute

abstract class

Like java, scala allows the definition of abstract classes, the methods of abstract classes are not allowed to be implemented, and abstract classes are not allowed to be instantiated. These are standard configurations of OOP

abstract class Fruit {
  def eat()  // This is an abstract method. If the subclass is not an abstract class, it must be implemented
  def get(): Unit = println("Got a fruit!")

class Apple extends Fruit {
  override def eat(): Unit = println("Ate an apple")

Call parent class construction

If a subclass inherits the parent class, it needs to call the construction of the parent class, which needs to be declared at the time of inheritance. You can use the construction of the subclass to initialize, for example:

object Test {
  def main(args: Array[String]): Unit = {
    val r = new Teacher("Tang")

class Person (name: String)

class Teacher (name:String) extends Person(name) {
  override def toString: String = "teacher's name = " + name


Polymorphism is the same as java, which is completed through upward transformation For example:

object Test {
  def main(args: Array[String]): Unit = {
    val f1: Fruit = new Apple
    val f2: Fruit = new Orange

abstract class Fruit {
  def eat()

class Apple extends Fruit {
  override def eat(): Unit = println("Eat apples")

class Orange extends Fruit {
  override def eat(): Unit = println("Eat oranges")


If final is added before the definition class, the class cannot be inherited:

final class class_name {

For methods, the representation method cannot be overridden, which is the same as java

Inheritance structure

As we know, all classes in java inherit from the Object class

In Scala, all classes inherit from the Any class It includes the following methods:

  • final def ==(that: Any): Boolean
  • final def !=(that: Any): Boolean
  • def equals(that: Any): Boolean
  • def hashCode: Int
  • def toString: String

These five methods can be found in java

Any has two direct subclasses, AnyValue and AnyRef The subclass of AnyValue is introduced earlier, in addition to the eight basic types of String plus a Unit These types cannot be new, only direct quantity can be used; Except for these nine classes, all other classes are from AnyRef Therefore, AnyRef is equivalent to the Object class of java

There is also a scala Null, all reference types are ancestors of this type So the following is written:

val p: Person = null

It can be explained by the upward transformation of OOP (because null must be the ancestor of Person)

However, except for the eight basic types of String, null assignment cannot be used:

val i: Int = null  // Error!!!

Because Null is not the ancestor of Int

scala also has a scala Nothing indicates that there is no value When the program throws an exception, it will return this thing It is the descendant of all types

The inheritance structure tree of Scala can be represented by the following figure:


It can be compared with the Java interface, but it is quite different from the interface In Scala, a class can't be said to implement Trait, but rather a class mixed with Trait

Traits can include abstract and non - abstract methods But unlike abstract classes, subclasses can be mixed with multiple characteristics; Only one subclass of an abstract class can inherit

Use with to blend in traits Traits generally make classes conform to some characteristics If you want to mix in traits, you must have existing extensions, otherwise an error will be reported This is because scala gives you priority to use abstract classes. Only when abstract classes can't satisfy you can you use traits For example:

trait Eatable {
  def eat()

trait Walkable {
  def walk(): Unit = println("walk!")

abstract class Person {
  def talk()

class Student extends Person with Eatable with Walkable {
  override def talk(): Unit = println("The students are talking!")
  override def eat(): Unit = println("Students eat!")

object Test {
  def main(args: Array[String]): Unit = {
    val student: Student = new Student
    val eat: Eatable = student
    val walk: Walkable = student
    val person: Person = student

This trait is a bit like inheritance Because traits can achieve specific methods

If there is a concrete method with the same name in the mixed characteristics, it may conflict after mixing, and the subclass must override this method



A fixed length, linear data structure The bottom layer of Scala is implemented by java arrays

Scala provides two types of arrays: Array and ArrayBuffer Among them, the length of the former is fixed and the length of the latter can be changed. Some data can be added and deleted, but the efficiency is low

Common operations for arrays are as follows:

// Define an array of length 3
val arr1 = new Array[String](3)

// Initialize array directly
val arr2 = Array[String]("abc", "123", "456")

// Without declaring generics, different types of data can be stored
val arr3 = Array("a", 1, 3, 9.0, "b")

// Use parentheses to access arrays

// Traversal array
for (str <- arr2) {

// Modify element
arr1(1) = "niubi"

Array has some useful API s. For example, concat can splice two arrays, and foreach can do something for each element of the array:

val arr1 = Array[Int](1, 2, 3, 4)
val arr2 = Array[Int](5, 6, 7)

val arr3 = Array.concat(arr1, arr2)
arr3.foreach {

There are many other API s, you can consult the documentation yourself


List has list and ListBuffer, of which the first is immutable and the second is variable

The definition List can be written as follows:

val list1 = List(2, 3, 5)
val list2 = "a" :: "b" :: "c" :: "d" :: "e" :: Nil

The second way of writing is to splice a list in order, and the last one must be Nil The '::' actually inserts an element at the first position in the list But the operand is an R - value

The following common methods can manipulate the elements of a List:

val list1 = List(2, 3, 5)
val list2 = "a" :: "b" :: "c" :: "d" :: "e" :: Nil


// Linked list
val list3 = list1 ::: list2

// Insert element backward
val list4 = list2 :+ "f"

// Insert element forward
val list5 = "z" +: list2

// Delete element
val list6 = list2.drop(1)

// Modify element
val list7 = list2.updated(2, "a")

Unlike java, the modification of List is realized by returning another List That is, the elements of the List itself cannot be changed

Variable lists and arrays

The above Array and List do not change themselves, but return a new collection, which is a waste of space

ArrayBuffer and ListBuffer can be changed, and can be converted to Array and List

val buffer = ArrayBuffer(4, 1, 4)
buffer.append(10, 20)

val arr = buffer.toArray

The usage of ListBuffer is the same


Range indicates the range of a data The to operator can be used to construct, and range can be converted to array or list:

val r = 1 to 10
val list = r.toList



In order to improve the random reading efficiency of List, Scala introduces a new set

The usage of Vector as like as two peas of List.


The characteristic of Set is that the stored elements are not allowed to be repeated and are out of order The usage is similar to List


Map is used to save key value pairs Map elements cannot be changed. Common operations are as follows:

// Create Map
val m1 = Map(1 -> "zhang", 2 -> "Li", 3 -> "Wang")

// Append element
val m2 = m1 + (4 -> "Zhao")

// Delete element
val m3 = m1 - 2

// Get element
println(m1.getOrElse(1, null))

// Traverse Map
for (key <- m1.keySet) {
    println(key + "," + m1.getOrElse(key, null))

// or
val ite = m1.iterator
for (t <- ite) {
    println(t._1 + "," + t._2)

// or
m1.foreach(t => println(t._1 + "," + t._2))

You can generate a Map through zip:

val l1 = List(1, 2, 3)
val l2 = List("a", "b", "c")

val map =


This can combine other lists into a Map


Represents a key value pair. A key can have multiple values A Tuple can be declared through parentheses, and the value can be obtained through "#":

val t = (1, "a", "b", 200)

Tuple stores up to 22 fields

Set general method

The basic collection objects contain the following methods (the following T indicates the type of collection storage element):

  • Exist (t = > Boolean): for a function, each time it receives the value in the collection, return true to indicate that the element exists and false to indicate that the element does not exist As long as one of all elements returns true, the whole function returns true
  • Sorted: returned after sorting the elements, sorted in ascending order
  • Sortwith ((T, t) = > Boolean): specify the sorting rules yourself
  • distinct: de duplication
  • reverse: reverses the entire collection
  • Reversemap (t = > unit): indicates that the element is reversed after some processing
  • contains(T): whether to include an element
  • startsWith(Seq[T]): whether to start with a collection
  • endsWith(Seq[T]): whether to end with a set

In addition, there are some general higher-order functions in the set:

  • Partition (t = > Boolean): split the collection according to a certain feature
  • Map (t = > unit): apply the function to each element to get a new set
  • Filter (t = > Boolean): filter the set according to a certain condition
  • Filternot (t = > Boolean): filter unqualified elements
  • Reduce ((T, t) = > t): apply two elements in the set to a function, and finally return a value
  • par: allows multithreading when calculating elements in a collection
  • Groupby (t = > any): grouping. Each element acts on the function and returns the same. It is divided into a group

Other features

generic paradigm

Scala is as like as two peas in Java. The only difference is that Scala uses brackets.


Usually, attributes declared with val or var allocate space directly However, if this variable is used later, the space is occupied all the time, which is a waste

When defining a variable, we can add a lazy before it, so that we can allocate space for this variable only when we know that this variable is used:

lazy val str = "hello"
...           // There is no space allocated here
println(str)  // Space is allocated for str here


Option can be expressed as a result in scala, which can have or have no value It has two implementations: some and None Some indicates that some values are returned, and None indicates that there is no value

Option needs to receive a generic type indicating what type of value is returned

For example, implement a division. If the divisor is 0, return None:

def div(x: Double, y: Double): Option[Double] = {
    if (y == 0) {
    else {
        Some(x / y)

println(div(20.0, 10.0).getOrElse(0.0))
println(div(10.0, 0).getOrElse(0.0))

The getOrElse() method receives a default value. If None is returned, the default value is returned; If Some is returned, the value of Some is returned

This avoids some exception handling

Sample class

The sample class is a special class This class must have construction parameters, and implements the serialization interface by default. It overrides the toString, equals and hashcode methods by default, and can directly generate objects without new

For example:

object Test {
  def main(args: Array[String]): Unit = {
    val p: Person = Person("zhang")

case class Person (name: String) {
  def getName: String = name

If new is not used, Scala's internal factory is used to instantiate the object The purpose of this class is to speed up the writing of java bean classes