第6章 面向对象
Scala 的面向对象思想和Java 的面向对象思想和概念是一致的。
Scala 中语法和 Java 不同,补充了更多的功能。
6.1类和对象详解
6.1.1组成结构
6.1.2构造器
每个类都有一个主构造器,这个构造器和类定义"交织"在一起类名后面的内容就是主构造器,如果参数列表为空的话,()可以省略
scala的类有且仅有一个主构造器,要想提供更加丰富的构造器,就需要使用辅助构造器,辅助构造器是可选的,它们叫做this def this
代码示例:
Scala // 类默认有一个无参的主构造函数 class User { }
val user: User = new User
// 两个参数的主构造函数 class User2(val name: String, age: Int) {
} val user2 = new User2("jim", 23) // 使用val修饰的变量默认是成员变量,对象可以访问 // user2.age // age没有使用val或者var修饰 所以不能被访问,他不是一个成员变量,而是一个局部变量
//辅助构造器 class User3 { var name: String = _ var age: Int = _ // 辅助构造函数 def this(name: String, age: Int) { // 构造函数中的首行必须调用主构造函数或者其他构造函数 this() this.name = name this.age = age } // 辅助构造函数 def this(msg: String) = { // 首行调用一个构造 this("ww", 12) println(msg) } } val u1 = new User3() val u2 = new User3("") val u3 = new User3("lisi", 23) println(u3.name) |
总结:
- 有两类构造器:主构造器,辅助构造器
- 构造器的定义位置:主构造器和类交织在一起,class Student2(val name: String, var age: Int)
- 辅助构造器是一个特殊的方法,定义在类中 def this(name:String,age:Int,gender:String)
- 辅助构造器,第一行必须调用主构造器(或者其他的辅助构造器)
- 辅助构造器的参数不能和主构造器的参数完全一致(参数个数,参数类型,参数顺序)
- 可以定义空参的辅助构造器,但是主构造器的参数必须进行初始化赋值
- 作用域:辅助构造器的变量作用域,只在方法中,主构造器的作用域是类中除了成员属性和成员方法之外的所有范围(可以通过反编译查看源码)
构造器的参数说明
- 主构造函数中使用val 和 var修饰的变量为成员变量
- val 修饰的变量默认只有getter方法 一要初始化
- var 修饰的变量默认有 get和set方法 直接点属性操作 使用 _ 占位可以稍后赋值
- @BeanProperty会生成getMsg setMsg方法
6.1.3成员方法/函数
在类的成员位置定义的函数或者方法是类的成员的一部分
6.1.4代码块
在类或者对象中的代码块在实例化的时候会被调用
- 在类成员位置的代码块 构造代码块 每次创建对象都会执行一次
- 在object中成员位置的代码块是静态代码块 只执行一次
6.1.5object类的底层原理
Scala package com.doit.day01.day02
//如果构造器中的变量,不加var 或者val 那他就是一个局部变量 //加了var 或者val 的话他就是一个私有的成员变量 class Student1(var id: Int, val name: String) {
def sayHello: Unit = { println(name + ":你好") }
val sayFunc = () => { println("hello:" + name) } }
object Student2{ var id: Int = 1 //如果在成员变量的位置上给一个_作为占位符,相当于是给他赋了一个默认值啊 var name: String =_
def sayHello: Unit = { println(name + ":你好") } val sayFunc = (x:String) => { println("hello:" + name + x) } }
object Demo01_面向对象 { def main(args: Array[String]): Unit = {
Student2.sayFunc("a")
val student1: Student1 = new Student1(1, "zhangsan") println(student1.name) println(student1.id) // student1.name = "lisi" 用val 修饰的,不能修改 student1.id = 2 println(student1.id)
student1.sayHello student1.sayFunc() println(Student2.name) } } |
java手写实现:
Java package com.doit;
public class Person { public static String getName(){ return Person$.person.getName(); }
public static Integer getAge(){ return Person$.person.getAge(); }
public static void setName(String name ){ Person$.person.setName(name); }
public static void setAge(Integer age ){ Person$.person.setAge(age); } }
class Person$ { //自己的对象 public static Person$ person ; //成员变量 private String name; private int age;
static { person = new Person$(); }
private Person$() { }
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; } }
class Test{ public static void main(String[] args) { Person person = new Person(); person.setName("张三"); person.setAge(18); String name1 = person.getName(); Integer age1 = person.getAge(); System.out.println(name1); System.out.println(age1); } } |
scala中底层反编译后的代码:
Java //decompiled from Student2$.class package com.doit.day01.day02;
import java.lang.invoke.SerializedLambda; import scala.Function1; import scala.Predef.; import scala.runtime.BoxedUnit;
public final class Student2$ { public static Student2$ MODULE$; private int id; private String name; private final Function1 sayFunc;
static { new Student2$(); }
public int id() { return this.id; }
public void id_$eq(final int x$1) { this.id = x$1; }
public String name() { return this.name; }
public void name_$eq(final String x$1) { this.name = x$1; }
public void sayHello() { .MODULE$.println((new StringBuilder(3)).append(this.name()).append(":你好").toString()); }
public Function1 sayFunc() { return this.sayFunc; }
// $FF: synthetic method public static final void $anonfun$sayFunc$1(final String x) { .MODULE$.println((new StringBuilder(6)).append("hello:").append(MODULE$.name()).append(x).toString()); }
private Student2$() { MODULE$ = this; this.id = 1; this.sayFunc = (x) -> { $anonfun$sayFunc$1(x); return BoxedUnit.UNIT; }; }
// $FF: synthetic method private static Object $deserializeLambda$(SerializedLambda var0) { return var0.lambdaDeserialize<invokedynamic>(var0); } }
//decompiled from Student2.class package com.doit.day01.day02;
import scala.Function1; import scala.reflect.ScalaSignature;
@ScalaSignature( bytes = "\u0006\u0001!;Q\u0001D\u0007\t\u0002Y1Q\u0001G\u0007\t\u0002eAQ\u0001I\u0001\u0005\u0002\u0005BqAI\u0001A\u0002\u0013\u00051\u0005C\u0004(\u0003\u0001\u0007I\u0011\u0001\u0015\t\r9\n\u0001\u0015)\u0003%\u0011%y\u0013\u00011AA\u0002\u0013\u0005\u0001\u0007C\u0005=\u0003\u0001\u0007\t\u0019!C\u0001{!Iq(\u0001a\u0001\u0002\u0003\u0006K!\r\u0005\u0006\u0001\u0006!\t!\u0011\u0005\b\u0005\u0006\u0011\r\u0011\"\u0001D\u0011\u00199\u0015\u0001)A\u0005\t\u0006A1\u000b^;eK:$(G\u0003\u0002\u000f\u001f\u0005)A-Y=1e)\u0011\u0001#E\u0001\u0006I\u0006L\b'\r\u0006\u0003%M\tA\u0001Z8ji*\tA#A\u0002d_6\u001c\u0001\u0001\u0005\u0002\u0018\u00035\tQB\u0001\u0005TiV$WM\u001c;3'\t\t!\u0004\u0005\u0002\u001c=5\tADC\u0001\u001e\u0003\u0015\u00198-\u00197b\u0013\tyBD\u0001\u0004B]f\u0014VMZ\u0001\u0007y%t\u0017\u000e\u001e \u0015\u0003Y\t!!\u001b3\u0016\u0003\u0011\u0002\"aG\u0013\n\u0005\u0019b\"aA%oi\u00061\u0011\u000eZ0%KF$\"!\u000b\u0017\u0011\u0005mQ\u0013BA\u0016\u001d\u0005\u0011)f.\u001b;\t\u000f5\"\u0011\u0011!a\u0001I\u0005\u0019\u0001\u0010J\u0019\u0002\u0007%$\u0007%\u0001\u0003oC6,W#A\u0019\u0011\u0005IJdBA\u001a8!\t!D$D\u00016\u0015\t1T#\u0001\u0004=e>|GOP\u0005\u0003qq\ta\u0001\u0015:fI\u00164\u0017B\u0001\u001e<\u0005\u0019\u0019FO]5oO*\u0011\u0001\bH\u0001\t]\u0006lWm\u0018\u0013fcR\u0011\u0011F\u0010\u0005\b[\u001d\t\t\u00111\u00012\u0003\u0015q\u0017-\\3!\u0003!\u0019\u0018-\u001f%fY2|W#A\u0015\u0002\u000fM\f\u0017PR;oGV\tA\t\u0005\u0003\u001c\u000bFJ\u0013B\u0001$\u001d\u0005%1UO\\2uS>t\u0017'\u0001\u0005tCf4UO\\2!\u0001" ) public final class Student2 { public static Function1 sayFunc() { return Student2$.MODULE$.sayFunc(); }
public static void sayHello() { Student2$.MODULE$.sayHello(); }
public static void name_$eq(final String x$1) { Student2$.MODULE$.name_$eq(var0); }
public static String name() { return Student2$.MODULE$.name(); }
public static void id_$eq(final int x$1) { Student2$.MODULE$.id_$eq(var0); }
public static int id() { return Student2$.MODULE$.id(); } } |
练一练
需求1:1.定义一个object,里面放一个成员:base = 100
2.定义一个工具方法:求两数之和,如果和<base 返回和,否则返回base
3.定义一个工具函数:求两数的差,并且返回(差值<base 就返回base,否则返回差值)
4.定义一个工具函数:求三个数的最大值,如果最大值<base 就返回base,否则返回最大值
Scala object Max { val base = 100
def sum(i: Int, j: Int) = { if (i + j < base) base else i + j }
val cha = (i: Int, j: Int) => { if (i - j < base) base else i - j }
val max = (a: Int, b: Int, c: Int) => { var mx = a if (b > mx) mx = b if (c > mx) mx = c if (mx > base) mx else base } } |
需求2:用java模拟一个object内部的实现原理,把需求1这个object类模拟出来
Java //函数对应的接口 package com.doit;
public interface Function3<U,V,Y,Z> { Z apply(U u,V v,Y y); }
package com.doit;
public interface Function2<U,V,T> { T apply(U u,V v); }
//对象的.class package com.doit;
//都是放的静态的 class Max { //这里面都是静态的,用Max$里面定义的对象去调用所有的成员属性,方法和函数 private static int getBase(){ return Max$.MODULE$.getBase(); }
private static int getMax(int a,int b,int c){ return Max$.MODULE$.getMax().apply(a,b,c); }
private static int getCha(int a,int b){ return Max$.MODULE$.getCha().apply(a,b); }
private static int getSum(int a,int b){ return Max$.MODULE$.getCha().apply(a,b); }
}
//类似于java中的.class class Max$ { //还要定义一个自己的对象,对象名字是MODULE$,为了上面静态的能访问到,所以他也要是静态的 public static Max$ MODULE$; //定义成员变量,val修饰的,在java中前面要加final修饰 private final Integer base = 100; //定义两个函数 //两个数求差的函数 private final Function2<Integer, Integer, Integer> cha = new Function2<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return integer + integer2; } };
//三个数求最大值的函数 private final Function3<Integer, Integer, Integer, Integer> max = new Function3<Integer, Integer, Integer, Integer>() { @Override public Integer apply(Integer a, Integer b, Integer c) { int mx = a; if (b > mx) mx = b; if (c > mx) mx = c; if (mx < base) mx = base; return mx; } };
//定义方法,两数求和 public int sum(int a ,int b ){ return a+b; }
//get和set方法 public int getBase(){ return base; } //base 是常量,所以这边不用写set方法 // private void setBase(int num){ // this.base = num; // }
//函数本质上也是一个类型哦,所以他也是成员变量的地位,需要写get方法哦
public Function2<Integer, Integer, Integer> getCha(){ return this.cha; }
public Function3<Integer, Integer, Integer,Integer> getMax(){ return this.max; }
static { new Max$(); }
private Max$() { MODULE$ = this; }
} |
6.1.6伴生类和伴生对象
条件 1:在同一个源文件中, 条件 2:对象名和类名相同
Scala //类名和object的名称一致 //类是对象的伴生类 //对象是类的伴生对象
class Demo6(val name: String) { } object Demo6 { } |
条件 2:伴生对象和伴生类之间可以互相访问彼此的私有属性和私有方法
Scala package com.doit.day01.day02
/** * 伴生对象的用途: * 1.可以将静态的成员变量和普通成员变量分别声明 * 2.伴生对象自己内部定义了一个apply方法,可以简化创建对象(类的实例构造) * 3.伴生对象自己定义了一个unapply方法,可以用于模式匹配 */ class Car(var brand: String, var price: Double) {
def sayHello(): Unit ={ println("hello") }
private val color: String = Car.color Car.start() }
object Car { var color :String = "red"
def start(): Unit ={ println("汽车启动了,嗡~~~~~~~~") } }
object Demo02_伴生对象 { def main(args: Array[String]): Unit = { val car: Car = new Car("华为", 9.9) println(car.brand) println(car.price) car.sayHello() Car.start() } } |
伴生对象的底层原理:
Java //decompiled from Car.class package com.doit.day01.day02;
import scala.Predef.; import scala.reflect.ScalaSignature;
@ScalaSignature( bytes = "\u0006\u0001E3A\u0001E\t\u00015!A\u0011\u0005\u0001BA\u0002\u0013\u0005!\u0005\u0003\u0005/\u0001\t\u0005\r\u0011\"\u00010\u0011!)\u0004A!A!B\u0013\u0019\u0003\u0002\u0003\u001c\u0001\u0005\u0003\u0007I\u0011A\u001c\t\u0011m\u0002!\u00111A\u0005\u0002qB\u0001B\u0010\u0001\u0003\u0002\u0003\u0006K\u0001\u000f\u0005\u0006\u007f\u0001!\t\u0001\u0011\u0005\u0006\u000b\u0002!\tAR\u0004\u0006\u000fFA\t\u0001\u0013\u0004\u0006!EA\t!\u0013\u0005\u0006\u007f)!\tA\u0013\u0005\b\u0017*\u0001\r\u0011\"\u0001#\u0011\u001da%\u00021A\u0005\u00025Caa\u0014\u0006!B\u0013\u0019\u0003\"\u0002)\u000b\t\u00031%aA\"be*\u0011!cE\u0001\u0006I\u0006L\bG\r\u0006\u0003)U\tQ\u0001Z1zaER!AF\f\u0002\t\u0011|\u0017\u000e\u001e\u0006\u00021\u0005\u00191m\\7\u0004\u0001M\u0011\u0001a\u0007\t\u00039}i\u0011!\b\u0006\u0002=\u0005)1oY1mC&\u0011\u0001%\b\u0002\u0007\u0003:L(+\u001a4\u0002\u000b\t\u0014\u0018M\u001c3\u0016\u0003\r\u0002\"\u0001J\u0016\u000f\u0005\u0015J\u0003C\u0001\u0014\u001e\u001b\u00059#B\u0001\u0015\u001a\u0003\u0019a$o\\8u}%\u0011!&H\u0001\u0007!J,G-\u001a4\n\u00051j#AB*ue&twM\u0003\u0002+;\u0005I!M]1oI~#S-\u001d\u000b\u0003aM\u0002\"\u0001H\u0019\n\u0005Ij\"\u0001B+oSRDq\u0001\u000e\u0002\u0002\u0002\u0003\u00071%A\u0002yIE\naA\u0019:b]\u0012\u0004\u0013!\u00029sS\u000e,W#\u0001\u001d\u0011\u0005qI\u0014B\u0001\u001e\u001e\u0005\u0019!u.\u001e2mK\u0006I\u0001O]5dK~#S-\u001d\u000b\u0003auBq\u0001N\u0003\u0002\u0002\u0003\u0007\u0001(\u0001\u0004qe&\u001cW\rI\u0001\u0007y%t\u0017\u000e\u001e \u0015\u0007\u0005\u001bE\t\u0005\u0002C\u00015\t\u0011\u0003C\u0003\"\u000f\u0001\u00071\u0005C\u00037\u000f\u0001\u0007\u0001(\u0001\u0005tCfDU\r\u001c7p)\u0005\u0001\u0014aA\"beB\u0011!IC\n\u0003\u0015m!\u0012\u0001S\u0001\u0006G>dwN]\u0001\nG>dwN]0%KF$\"\u0001\r(\t\u000fQj\u0011\u0011!a\u0001G\u000511m\u001c7pe\u0002\nQa\u001d;beR\u0004" ) public class Car { private String brand; private double price;
public static void start() { Car$.MODULE$.start(); }
public static void color_$eq(final String x$1) { Car$.MODULE$.color_$eq(var0); }
public static String color() { return Car$.MODULE$.color(); }
public String brand() { return this.brand; }
public void brand_$eq(final String x$1) { this.brand = x$1; }
public double price() { return this.price; }
public void price_$eq(final double x$1) { this.price = x$1; }
public void sayHello() { .MODULE$.println("hello"); }
public Car(final String brand, final double price) { this.brand = brand; this.price = price; super(); } }
//decompiled from Car$.class package com.doit.day01.day02;
import scala.Predef.;
public final class Car$ { public static Car$ MODULE$; private String color;
static { new Car$(); }
public String color() { return this.color; }
public void color_$eq(final String x$1) { this.color = x$1; }
public void start() { .MODULE$.println("汽车启动了,嗡~~~~~~~~"); }
private Car$() { MODULE$ = this; this.color = "red"; } }
|
图示:
伴生对象用途:
- 可以将静态的成员变量和普通成员变量分别声明(class中没办法添加静态成员,需要经过object类来添加)
- 伴生对象自己内部定义了一个apply方法,可以简化创建对象(类的实例构造)
- 伴生对象自己定义了一个unapply方法,可以用于模式匹配
6.1.6apply方法
使用此方法时,可以在main函数中不通过new来创建一个对象,即可以不用专门的一次一次地进行实例化,加载创建对象的这个类的时候,会自动调用apply这个方法,类似Java中的static静态块。
- 通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。
- apply 方法可以重载。
- Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
- 当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实是伴生对象的 apply 方法。
Scala object Test { def main(args: Array[String]): Unit = { //(1)通过伴生对象的 apply 方法,实现不使用 new 关键字创建对象。 val p1 = Person() println("p1.name=" + p1.name) val p2 = Person("bobo") println("p2.name=" + p2.name) } } //(2)如果想让主构造器变成私有的,可以在()之前加上 private class Person private(cName: String) { var name: String = cName }
object Person { def apply(): Person = { println("apply 空参被调用") new Person("xx") } def apply(name: String): Person = { println("apply 有参被调用") new Person(name) } } |
6.2权限修饰符
在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。
(1)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。
(2)private 为私有权限,只在类的内部和伴生对象中可用。
(3)protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以访问,同包无法访问。
(4)private[包名]增加包访问权限,包名下的其他类也可以使用
代码演示:
Scala class Person { private var name: String = "bobo" protected var age: Int = 18 private[test] var sex: String = "男" def say(): Unit = { println(name) } } object Person { def main(args: Array[String]): Unit = { val person = new Person person.say() println(person.name) println(person.age) } } class Teacher extends Person { def test(): Unit = { this.age this.sex } } class Animal { def test: Unit = { new Person().sex } } |
6.3特质和抽象类
6.3.1特质
Trait(特质)相当于 java 的接口。比接口功能更强大。特质中可以定义属性和抽象方法和方法的实现。
Scala 的类只能够继承单一父类,但是可以实现(继承,混入)多个特质(Trait),使用的关键字是 with 和 extends
基本语法
Scala trait 特质名 { trait 主体 }
//如何使用特质: 没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 … 有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3… |
代码演示:
Scala trait PersonTrait { // 声明属性 var name:String = _ // 声明方法 def eat():Unit={ } // 抽象属性 var age:Int // 抽象方法 def say():Unit } |
6.3.1.2特质的动态混入
1.创建对象时混入 trait,而无需使类混入该 trait
2.如果混入的 trait 中有未实现的方法,则需要实现
代码演示:
Scala trait PersonTrait { //(1)特质可以同时拥有抽象方法和具体方法 // 声明属性 var name: String = _ // 抽象属性 var age: Int // 声明方法 def eat(): Unit = { println("eat") } // 抽象方法 def say(): Unit } trait SexTrait { var sex: String } //(2)一个类可以实现/继承多个特质 //(3)所有的 Java 接口都可以当做 Scala 特质使用 class Teacher extends PersonTrait with java.io.Serializable { override def say(): Unit = { println("say") } override var age: Int = _ } object TestTrait { def main(args: Array[String]): Unit = { val teacher = new Teacher teacher.say() teacher.eat() //(4)动态混入:可灵活的扩展类的功能 val t2 = new Teacher with SexTrait { override var sex: String = "男" } //调用混入 trait 的属性 println(t2.sex) } } |
6.3.2抽象类
在 Scala 中, 使用 abstract 修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法(抽象方法)和具体实现的方法。 含有抽象方法的类就是抽象类
示例:
Scala /* * abstract 修饰的类是一个抽象类 * */ abstract class Animal { println("Animal's constructor ....") // 定义一个 name 属性 val name: String = "animal" // 没有任何实现的方法 def sleep() // 带有具体的实现的方法 def eat(f: String): Unit = { println(s"$f") } } |
抽象类的继承和重写
- 如果父类为抽象类,那么子类要么也是抽象类,要么就需要重写父类中的所有的抽象方法和抽象的成员变量
- 重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。
- 子类中调用父类的方法使用 super 关键字,在子类重写了父类的方法后,如果不加super,直接写方法名调用的就是子类重写后的,如果加了,调用的还是父类的
- 子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var(var修饰具体方法和变量不好重写)
因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写 |
6.4样例类
使用case修饰的类就是样例类(封装数据,模式匹配)
- 构造器中的参数默认是val修饰的[成员,赋值1次]
- 样例类会自动创建伴生对象, 同时在里面实现;的apply和unapply方法 ,创建对象的时候不用new
- 很好的支持匹配模式
- 默认实现了自己的toString , hashCode , copy , equals,序列化方法
定义一个样例类:
Scala case class Person(var name:String , var age:Int) {}//如果类中没有别的需要定义的,可以不写大括号 |
反编译之后的结果:
Scala //decompiled from Person$.class package com.doit.day01.day02;
import scala.Option; import scala.Serializable; import scala.Some; import scala.Tuple2; import scala.None.; import scala.runtime.AbstractFunction2; import scala.runtime.BoxesRunTime;
public final class Person$ extends AbstractFunction2 implements Serializable { public static Person$ MODULE$;
static { new Person$(); }
public final String toString() { return "Person"; }
public Person apply(final String name, final int age) { return new Person(name, age); }
public Option unapply(final Person x$0) { return (Option)(x$0 == null ? .MODULE$ : new Some(new Tuple2(x$0.name(), BoxesRunTime.boxToInteger(x$0.age())))); }
private Object readResolve() { return MODULE$; }
// $FF: synthetic method // $FF: bridge method public Object apply(final Object v1, final Object v2) { return this.apply((String)v1, BoxesRunTime.unboxToInt(v2)); }
private Person$() { MODULE$ = this; } }
//decompiled from Person.class package com.doit.day01.day02;
import scala.Function1; import scala.Option; import scala.Product; import scala.Serializable; import scala.collection.Iterator; import scala.reflect.ScalaSignature; import scala.runtime.BoxesRunTime; import scala.runtime.Statics; import scala.runtime.ScalaRunTime.;
@ScalaSignature( bytes = "\u0006\u0001\u0005Uc\u0001\u0002\u000e\u001c\u0001\u0012B\u0001\"\r\u0001\u0003\u0012\u0004%\tA\r\u0005\t}\u0001\u0011\t\u0019!C\u0001\u007f!AQ\t\u0001B\tB\u0003&1\u0007\u0003\u0005G\u0001\tE\r\u0011\"\u0001H\u0011!Y\u0005A!a\u0001\n\u0003a\u0005\u0002\u0003(\u0001\u0005#\u0005\u000b\u0015\u0002%\t\u000b=\u0003A\u0011\u0001)\t\u000fU\u0003\u0011\u0011!C\u0001-\"9\u0011\fAI\u0001\n\u0003Q\u0006bB3\u0001#\u0003%\tA\u001a\u0005\bQ\u0002\t\t\u0011\"\u0011j\u0011\u001d\t\b!!A\u0005\u0002\u001dCqA\u001d\u0001\u0002\u0002\u0013\u00051\u000fC\u0004y\u0001\u0005\u0005I\u0011I=\t\u0013\u0005\u0005\u0001!!A\u0005\u0002\u0005\r\u0001\"CA\u0007\u0001\u0005\u0005I\u0011IA\b\u0011%\t\t\u0002AA\u0001\n\u0003\n\u0019\u0002C\u0005\u0002\u0016\u0001\t\t\u0011\"\u0011\u0002\u0018\u001dI\u00111D\u000e\u0002\u0002#\u0005\u0011Q\u0004\u0004\t5m\t\t\u0011#\u0001\u0002 !1q\n\u0006C\u0001\u0003[A\u0011\"!\u0005\u0015\u0003\u0003%)%a\u0005\t\u0013\u0005=B#!A\u0005\u0002\u0006E\u0002\"CA\u001c)\u0005\u0005I\u0011QA\u001d\u0011%\tY\u0005FA\u0001\n\u0013\tiE\u0001\u0004QKJ\u001cxN\u001c\u0006\u00039u\tQ\u0001Z1zaIR!AH\u0010\u0002\u000b\u0011\f\u0017\u0010M\u0019\u000b\u0005\u0001\n\u0013\u0001\u00023pSRT\u0011AI\u0001\u0004G>l7\u0001A\n\u0005\u0001\u0015Zc\u0006\u0005\u0002'S5\tqEC\u0001)\u0003\u0015\u00198-\u00197b\u0013\tQsE\u0001\u0004B]f\u0014VM\u001a\t\u0003M1J!!L\u0014\u0003\u000fA\u0013x\u000eZ;diB\u0011aeL\u0005\u0003a\u001d\u0012AbU3sS\u0006d\u0017N_1cY\u0016\fAA\\1nKV\t1\u0007\u0005\u00025w9\u0011Q'\u000f\t\u0003m\u001dj\u0011a\u000e\u0006\u0003q\r\na\u0001\u0010:p_Rt\u0014B\u0001\u001e(\u0003\u0019\u0001&/\u001a3fM&\u0011A(\u0010\u0002\u0007'R\u0014\u0018N\\4\u000b\u0005i:\u0013\u0001\u00038b[\u0016|F%Z9\u0015\u0005\u0001\u001b\u0005C\u0001\u0014B\u0013\t\u0011uE\u0001\u0003V]&$\bb\u0002#\u0003\u0003\u0003\u0005\raM\u0001\u0004q\u0012\n\u0014!\u00028b[\u0016\u0004\u0013aA1hKV\t\u0001\n\u0005\u0002'\u0013&\u0011!j\n\u0002\u0004\u0013:$\u0018aB1hK~#S-\u001d\u000b\u0003\u00016Cq\u0001R\u0003\u0002\u0002\u0003\u0007\u0001*\u0001\u0003bO\u0016\u0004\u0013A\u0002\u001fj]&$h\bF\u0002R'R\u0003\"A\u0015\u0001\u000e\u0003mAQ!M\u0004A\u0002MBQAR\u0004A\u0002!\u000bAaY8qsR\u0019\u0011k\u0016-\t\u000fEB\u0001\u0013!a\u0001g!9a\t\u0003I\u0001\u0002\u0004A\u0015AD2paf$C-\u001a4bk2$H%M\u000b\u00027*\u00121\u0007X\u0016\u0002;B\u0011alY\u0007\u0002?*\u0011\u0001-Y\u0001\nk:\u001c\u0007.Z2lK\u0012T!AY\u0014\u0002\u0015\u0005tgn\u001c;bi&|g.\u0003\u0002e?\n\tRO\\2iK\u000e\\W\r\u001a,be&\fgnY3\u0002\u001d\r|\u0007/\u001f\u0013eK\u001a\fW\u000f\u001c;%eU\tqM\u000b\u0002I9\u0006i\u0001O]8ek\u000e$\bK]3gSb,\u0012A\u001b\t\u0003WBl\u0011\u0001\u001c\u0006\u0003[:\fA\u0001\\1oO*\tq.\u0001\u0003kCZ\f\u0017B\u0001\u001fm\u00031\u0001(o\u001c3vGR\f%/\u001b;z\u00039\u0001(o\u001c3vGR,E.Z7f]R$\"\u0001^<\u0011\u0005\u0019*\u0018B\u0001<(\u0005\r\te.\u001f\u0005\b\t6\t\t\u00111\u0001I\u0003=\u0001(o\u001c3vGRLE/\u001a:bi>\u0014X#\u0001>\u0011\u0007mtH/D\u0001}\u0015\tix%\u0001\u0006d_2dWm\u0019;j_:L!a ?\u0003\u0011%#XM]1u_J\f\u0001bY1o\u000bF,\u0018\r\u001c\u000b\u0005\u0003\u000b\tY\u0001E\u0002'\u0003\u000fI1!!\u0003(\u0005\u001d\u0011un\u001c7fC:Dq\u0001R\b\u0002\u0002\u0003\u0007A/\u0001\u0005iCND7i\u001c3f)\u0005A\u0015\u0001\u0003;p'R\u0014\u0018N\\4\u0015\u0003)\fa!Z9vC2\u001cH\u0003BA\u0003\u00033Aq\u0001\u0012\n\u0002\u0002\u0003\u0007A/\u0001\u0004QKJ\u001cxN\u001c\t\u0003%R\u0019B\u0001FA\u0011]A9\u00111EA\u0015g!\u000bVBAA\u0013\u0015\r\t9cJ\u0001\beVtG/[7f\u0013\u0011\tY#!\n\u0003#\u0005\u00137\u000f\u001e:bGR4UO\\2uS>t'\u0007\u0006\u0002\u0002\u001e\u0005)\u0011\r\u001d9msR)\u0011+a\r\u00026!)\u0011g\u0006a\u0001g!)ai\u0006a\u0001\u0011\u00069QO\\1qa2LH\u0003BA\u001e\u0003\u000f\u0002RAJA\u001f\u0003\u0003J1!a\u0010(\u0005\u0019y\u0005\u000f^5p]B)a%a\u00114\u0011&\u0019\u0011QI\u0014\u0003\rQ+\b\u000f\\33\u0011!\tI\u0005GA\u0001\u0002\u0004\t\u0016a\u0001=%a\u0005Y!/Z1e%\u0016\u001cx\u000e\u001c<f)\t\ty\u0005E\u0002l\u0003#J1!a\u0015m\u0005\u0019y%M[3di\u0002" ) public class Person implements Product, Serializable { private String name; private int age;
public static Option unapply(final Person x$0) { return Person$.MODULE$.unapply(var0); }
public static Person apply(final String name, final int age) { return Person$.MODULE$.apply(var0, var1); }
public static Function1 tupled() { return Person$.MODULE$.tupled(); }
public static Function1 curried() { return Person$.MODULE$.curried(); }
public String name() { return this.name; }
public void name_$eq(final String x$1) { this.name = x$1; }
public int age() { return this.age; }
public void age_$eq(final int x$1) { this.age = x$1; }
public Person copy(final String name, final int age) { return new Person(name, age); }
public String copy$default$1() { return this.name(); }
public int copy$default$2() { return this.age(); }
public String productPrefix() { return "Person"; }
public int productArity() { return 2; }
public Object productElement(final int x$1) { Object var10000; switch(x$1) { case 0: var10000 = this.name(); break; case 1: var10000 = BoxesRunTime.boxToInteger(this.age()); break; default: throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); }
return var10000; }
public Iterator productIterator() { return .MODULE$.typedProductIterator(this); }
public boolean canEqual(final Object x$1) { return x$1 instanceof Person; }
public int hashCode() { int var1 = -889275714; var1 = Statics.mix(var1, Statics.anyHash(this.name())); var1 = Statics.mix(var1, this.age()); return Statics.finalizeHash(var1, 2); }
public String toString() { return .MODULE$._toString(this); }
public boolean equals(final Object x$1) { boolean var6; if (this != x$1) { label55: { boolean var2; if (x$1 instanceof Person) { var2 = true; } else { var2 = false; }
if (var2) { label38: { label37: { Person var4 = (Person)x$1; String var10000 = this.name(); String var5 = var4.name(); if (var10000 == null) { if (var5 != null) { break label37; } } else if (!var10000.equals(var5)) { break label37; }
if (this.age() == var4.age() && var4.canEqual(this)) { var6 = true; break label38; } }
var6 = false; }
if (var6) { break label55; } }
var6 = false; return var6; } }
var6 = true; return var6; }
public Person(final String name, final int age) { this.name = name; this.age = age; super(); Product.$init$(this); } } |
case class 和 class 的一些区别:
- case class 在初始化的时候,不用 new,而普通类初始化时必须要 new。
- case class 重写了 toString 方法。 默认实现了 equals 和 hashCode
- case class 实现了序列化接口 with Serializable
- case class 支持模式匹配(最重要的特征),所有 case class 必须要有参数列表
- 有参数用 case class,无参用 case object
6.5继承和多态
基本语法
class 子类名 extends 父类名 { 类体 }
(1)子类继承父类的属性和方法
(2)scala 是单继承
案例实操:
(1)子类继承父类的属性和方法
(2)继承的调用顺序:父类构造器->子类构造器
Scala class Person(nameParam: String) { var name = nameParam var age: Int = _ def this(nameParam: String, ageParam: Int) { this(nameParam) this.age = ageParam println("父类辅助构造器") } println("父类主构造器") } class Emp(nameParam: String, ageParam: Int) extends Person(nameParam, ageParam) { var empNo: Int = _ def this(nameParam: String, ageParam: Int, empNoParam: Int) { this(nameParam, ageParam) this.empNo = empNoParam println("子类的辅助构造器") } println("子类主构造器") } object Test { def main(args: Array[String]): Unit = { new Emp("z3", 11,1001) } } |
练一练:
定义一个order类 属性:user_id , order_id,goods_id,category_id,price,goods_num 需求1:对10个订单的金额大小的升序排列 需求2:对10个订单的金额大小的降序排列 需求3:统计每一种品类下的订单总额 需求4:统计每一个用户的订单总额 需求5:找出每个用户金额最大的哪个订单 需求6:找出每一种品类中金额最大的订单 需求7:找出订单金额最大的两个订单 需求8:找出订单金额最小的两个订单 |
第 7 章 集合
scala中的集合分为两种 ,可变集合和不可变集合, 不可变集合可以安全的并发的访问!
集合的类主要在一下两个包中
- 可变集合包 scala.collection.mutable
- 不可变集合包 scala.collection.immutable 默认的
Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象 建议:在操作集合的时候,不可变用符号,可变用方法 |
scala默认使用的是不可变的集合 , 因此使用可变的集合需要导入可变集合的包
scala的集合主要分成三大类
- Seq 序列
- Set 不重复集
- Map 键值映射集
注意: 所有的集合都继承自Iterator迭代器这个特质 |
不可变集合继承图
7.1迭代器(重点)
7.1.1java中的iterator
在java中用迭代器读取文件中的数据,每次返回一行数据
Java package com.doit;
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Iterator;
class MyHero implements Iterator<String> { BufferedReader buffer = null; String line = null;
public MyHero() { try { buffer = new BufferedReader(new FileReader("data/hero.txt")); } catch (FileNotFoundException e) { e.printStackTrace(); } }
@Override public boolean hasNext() { try { line = buffer.readLine(); } catch (IOException e) { e.printStackTrace(); } return line != null; }
@Override public String next() { return line; } }
public class MyIterator{ public static void main(String[] args) { MyHero myHero = new MyHero(); while (myHero.hasNext()){ System.out.println(myHero.next()); } } } |
在java中用迭代器读取mysql表中的数据,每次返回一行数据
Java package com.doit;
import java.sql.*; import java.util.Iterator;
public class ReadTable implements Iterator<Login> { ResultSet resultSet = null; public ReadTable(){ try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } try { Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/football", "root", "123456"); PreparedStatement pps = conn.prepareStatement("select * from login "); resultSet = pps.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } }
@Override public boolean hasNext() { boolean flag = false; try { flag = resultSet.next(); } catch (SQLException e) { e.printStackTrace(); } return flag; }
@Override public Login next() { Login login = new Login(); try { login.setId(resultSet.getInt(1)); login.setUser_id(resultSet.getInt(2)); login.setClient_id(resultSet.getInt(3)); login.setDate(resultSet.getString(4)); } catch (SQLException e) { e.printStackTrace(); } return login; }
}
class Login { private int id; private int user_id; private int client_id; private String date;
public Login() { }
public Login(int id, int user_id, int client_id, String date) { this.id = id; this.user_id = user_id; this.client_id = client_id; this.date = date; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getUser_id() { return user_id; }
public void setUser_id(int user_id) { this.user_id = user_id; }
public int getClient_id() { return client_id; }
public void setClient_id(int client_id) { this.client_id = client_id; }
public String getDate() { return date; }
public void setDate(String date) { this.date = date; }
@Override public String toString() { return "login{" + "id=" + id + ", user_id=" + user_id + ", client_id=" + client_id + ", date='" + date + '\'' + '}'; } } |
7.1.2java中的Iterable
代表可迭代的,返回的是一个迭代器
Java package com.doit;
import java.util.Iterator;
public class ReadTableIterable implements Iterable<Login>{ @Override public Iterator iterator() { return new ReadTable(); } }
//测试 package com.doit;
import java.util.Iterator;
public class Test3 { public static void main(String[] args) { ReadTableIterable logins = new ReadTableIterable(); //可迭代的都会有一个迭代器对象,获取出来后用hasnext next获取数据 Iterator iterator = logins.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //可迭代的java底层都封装了增强for循环,也可以直接使用 for (Login login : logins) { System.out.println(login); } } } |
7.1.3scala中的 iterator
Scala package com.doit.day01.day02
import scala.io.{BufferedSource, Source}
object MyIter { def main(args: Array[String]): Unit = { val iter: MyIter = new MyIter while (iter.hasNext){ println(iter.next()) } }
}
class MyIter extends Iterator[String]{ //读取数据 private val source: BufferedSource = Source.fromFile("data/hero.txt") private val lines: Iterator[String] = source.getLines() //用scala中返回迭代器中的hasNext方法直接判断 override def hasNext: Boolean = lines.hasNext //用scala中返回迭代器中的next方法获取数据 override def next(): String = lines.next() } |
7.1.4scala中的Iterable
Scala package com.doit.day01.day02
import scala.io.{BufferedSource, Source}
object MyIter { def main(args: Array[String]): Unit = { val iter: MyIter1 = new MyIter1 val iterator: Iterator[String] = iter.iterator while (iterator.hasNext){ println(iterator.next()) }
for (elem <- iter) { println(elem) } } }
class MyIter1 extends Iterable[String]{ override def iterator: Iterator[String] = new MyIter } |
7.2比较器
7.2.1java中的比较器 Comparator
Java package com.doit;
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator;
public class Test3 { public static void main(String[] args) { Order or1 = new Order("001", 100, "2022-7-12"); Order or2 = new Order("002", 99, "2022-7-11"); Order or3 = new Order("003", 88, "2022-7-15"); Order or4 = new Order("004", 103, "2022-7-13"); Order or5 = new Order("005", 55, "2022-7-10");
ArrayList<Order> list = new ArrayList<>(); list.add(or1); list.add(or2); list.add(or3); list.add(or4); list.add(or5); Collections.sort(list,new ComparatorDeme()); System.out.println(list); Collections.sort(list,new ComparatorDeme1()); System.out.println(list); } }
class ComparatorDeme implements Comparator<Order>{
@Override public int compare(Order o1, Order o2) { return -o1.getOrderAmount() + o2.getOrderAmount(); } }
class ComparatorDeme1 implements Comparator<Order>{
@Override public int compare(Order o1, Order o2) { return o1.getOrderTime().compareTo(o2.getOrderTime()); } } |
7.2.2java中的比较器 Comparable
Java package com.doit; //类实现Comparable 接口,重写里面的compareTo 方法 public class Order2 implements Comparable<Order2>{ private String orderId; private int orderAmount; private String orderTime;
public Order2() { }
public Order2(String orderId, int orderAmount, String orderTime) { this.orderId = orderId; this.orderAmount = orderAmount; this.orderTime = orderTime; }
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public int getOrderAmount() { return orderAmount; }
public void setOrderAmount(int orderAmount) { this.orderAmount = orderAmount; }
public String getOrderTime() { return orderTime; }
public void setOrderTime(String orderTime) { this.orderTime = orderTime; }
@Override public String toString() { return "Order{" + "orderId='" + orderId + '\'' + ", orderAmount=" + orderAmount + ", orderTime='" + orderTime + '\'' + '}'; }
@Override public int compareTo(Order2 o) { return this.orderAmount - o.orderAmount; } }
package com.doit;
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator;
public class Test3 { public static void main(String[] args) { // Order or1 = new Order("001", 100, "2022-7-12"); // Order or2 = new Order("002", 99, "2022-7-11"); // Order or3 = new Order("003", 88, "2022-7-15"); // Order or4 = new Order("004", 103, "2022-7-13"); // Order or5 = new Order("005", 55, "2022-7-10"); // // ArrayList<Order> list = new ArrayList<>(); // list.add(or1); // list.add(or2); // list.add(or3); // list.add(or4); // list.add(or5); // Collections.sort(list,new ComparatorDeme()); // System.out.println(list); // Collections.sort(list,new ComparatorDeme1()); // System.out.println(list); // System.out.println("===========华丽的分割线==========");
Order2 o1 = new Order2("001", 100, "2022-7-12"); Order2 o2 = new Order2("002", 99, "2022-7-11"); Order2 o3 = new Order2("003", 88, "2022-7-15"); Order2 o4 = new Order2("004", 103, "2022-7-13"); Order2 o5 = new Order2("005", 55, "2022-7-10");
ArrayList<Order2> list1 = new ArrayList<>(); list1.add(o1); list1.add(o2); list1.add(o3); list1.add(o4); list1.add(o5); //这边就不需要再传入比较器了 Collections.sort(list1); System.out.println(list1); } } |
7.2.3scala中的比较器 Ordering 类比于java中的Comparator
Scala package com.doit.day01.day02
import scala.util.Sorting object Demo_Ordering { def main(args: Array[String]): Unit = { val e1: Employee = new Employee(1, "涛哥", 10000) val e2: Employee = new Employee(2, "星哥", 8000) val e3: Employee = new Employee(3, "行哥", 5000) val e4: Employee = new Employee(4, "源哥", 3500) val e5: Employee = new Employee(5, "娜姐", 2000) val list: Array[Employee] = List(e1, e2, e3, e4, e5).toArray Sorting.quickSort(list)(MyOrdering()) println(list.mkString(","))
} } case class MyOrdering() extends Ordering[Employee] { override def compare(x: Employee, y: Employee): Int = (x.salary - y.salary).toInt }
class Employee(val id:Int,val name:String,val salary:Double){
override def toString = s"Employee(id=$id, name=$name, salary=$salary)" } |
7.2.4scala中的比较器 Ordered 类比于java中的Comparable
Scala package com.doit.day01.day02
import scala.util.Sorting
object Demo_Ordering { def main(args: Array[String]): Unit = { val e1: Employee = new Employee(1, "涛哥", 10000) val e2: Employee = new Employee(2, "星哥", 8000) val e3: Employee = new Employee(3, "行哥", 5000) val e4: Employee = new Employee(4, "源哥", 3500) val e5: Employee = new Employee(5, "娜姐", 2000) val list: Array[Employee] = List(e1, e2, e3, e4, e5).toArray Sorting.quickSort(list) println(list.mkString(",")) } }
class Employee(val id:Int,val name:String,val salary:Double) extends Ordered[Employee]{
override def toString = s"Employee(id=$id, name=$name, salary=$salary)"
override def compare(that: Employee): Int = (this.salary - that.salary).toInt } |
7.3序列
许多数据结构是序列型的,也就是说,元素可以按特定的顺序访问,如:元素的插入顺
序或其他特定顺序。collection.Seq是一个trait,是所有可变或不可变序列类型的抽象,其子trait collection.mutable.Seq及collection.immutable.Seq分别对应可变和不可变序列。
从上面的图中可以看出Array,String ,List都属于序列
7.3.1不可变数组
数组的基本操作 , scala中的数组和java中的不太一样 ,这里的数组类似于一个数组对象 .有自己的方法!!
7.1.1.1数组的定义方式
方式一:创建一个长度固定的数组,后面再赋值
Scala object TestArray{ def main(args: Array[String]): Unit = { //(1)数组定义 val arr01 = new Array[Int](4) println(arr01.length) // 4 //(2)数组赋值 //(2.1)修改某个元素的值 arr01(3) = 10 //(2.2)采用方法的形式给数组赋值 arr01.update(0,1) //(3)遍历数组 //(3.1)查看数组 println(arr01.mkString(",")) //(3.2)普通遍历 for (i <- arr01) { println(i) } //(3.3)简化遍历 def printx(elem:Int): Unit = { println(elem) } arr01.foreach(printx) // arr01.foreach((x)=>{println(x)}) // arr01.foreach(println(_)) arr01.foreach(println) //(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组) println(arr01) val ints: Array[Int] = arr01 :+ 5 println(ints) } } |
方式二:使用 apply 方法创建数组对象,并且在定义数组的时候直接赋初始值
代码示例:
Scala object TestArray{ def main(args: Array[String]): Unit = { var arr02 = Array(1, 3, "bobo") println(arr02.length) for (i <- arr02) { println(i) } } } |
数组中的方法:
Scala val arr = Array(1,3,5,7,9,2,6,4) // 数组中的最大和最小值 val min: Int = arr.min val max: Int = arr.max // 首个元素 val head: Int = arr.head //最后一个元素 val last: Int = arr.last // 去除首个元素的子数组 val arr11: Array[Int] = arr.tail // 将数组转换成List集合 val list: List[Int] = arr.toList // 获取和后面数组中不同的元素 val diff: Array[Int] = arr.diff(Array(1,111,222)) //求数组元素的和 val sum: Int = arr.sum // 数组的长度 arr.length //修改指定位置的元素 arr.update(1,100) // 取出数组中的前n个元素 val arr3: Array[Int] = arr.take(3) // 后面添加一个元素 生成 新的数组 val arr2: Array[Int] = arr.:+(11) // 后面添加一个数组 val res = arr ++ arr3 // 统计符合条件的个数 val i: Int = arr.count(_>2) // 数组反转 arr.reverse // 将不可变数组转换成可变数组 val buffer: mutable.Buffer[Int] = arr.toBuffer |
练一练:
需求一:有一个10个长度的数组,第一个位置放得是3,后面每个位置都是前一个位置的2倍加1,
现需要打印这个数组,然后将这个数组中的奇数位置和偶数位置互换
Scala package com.doit.day01.day02
/** * 需求一:有一个10个位置的数组,第一个位置放得是3,后面每个位置都是前一个位置的2倍加1, * 现需要打印这个数组,然后将这个数组中的奇数位置和偶数位置互换 */ object Test1 { def main(args: Array[String]): Unit = {
val arr = new Array[Int](10) arr(0) = 3 //构建数据 for (elem <- 1 to 9) arr(elem) = arr(elem - 1) * 2 + 1 //打印这个数组 println(arr.mkString(",")) //将这个数组中的奇数位置和偶数位置互换 for (elem <- 0 until arr.length) { if((elem+1) %2 == 1){ var tmp = arr(elem) arr(elem) = arr(elem + 1) arr(elem + 1) = tmp } } println(arr.mkString(",")) } } |
7.3.2可变数组--> ArrayBuffer
导入可变数组 : import scala.collection.mutable.ArrayBuffer ,可以修改元素的数组为可变数组
定义:
定义变长数组 val arr01 = ArrayBuffer[Any](3, 2, 5) (1)[Any]存放任意数据类型 (2)(3, 2, 5)初始化好的三个元素 (3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer |
实例操作:
Scala import scala.collection.mutable.ArrayBuffer object TestArrayBuffer { def main(args: Array[String]): Unit = { //(1)创建并初始赋值可变数组 val arr01 = ArrayBuffer[Any](1, 2, 3) //(2)遍历数组 for (i <- arr01) { println(i) } println(arr01.length) // 3 println("arr01.hash=" + arr01.hashCode()) //(3)增加元素 //(3.1)追加数据 arr01.+=(4) //(3.2)向数组最后追加数据 arr01.append(5,6) //(3.3)向指定的位置插入数据 arr01.insert(0,7,8) println("arr01.hash=" + arr01.hashCode()) //(4)修改元素 arr01(1) = 9 //修改第 2 个元素的值 println("--------------------------") for (i <- arr01) { println(i) } println(arr01.length) // 5 } } |
7.3.3不可变 List
说明:
(1)List 默认为不可变集合 (2)创建一个 List(数据有顺序,可重复) (3)遍历 List (4)List 增加数据 (5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化 (6)取指定数据 (7)空集合 Nil |
示例:
Scala object TestList { def main(args: Array[String]): Unit = { //(1)List 默认为不可变集合 //(2)创建一个 List(数据有顺序,可重复) val list: List[Int] = List(1,2,3,4,3) //(7)空集合 Nil val list5 = 1::2::3::4::Nil //(4)List 增加数据 //(4.1)::的运算规则从右向左 //val list1 = 5::list val list1 = 7::6::5::list //(4.2)添加到第一个元素位置 val list2 = list.+:(5) //(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化 val list3 = List(8,9) //val list4 = list3::list1 val list4 = list3:::list1 //(6)取指定数据 println(list(0)) //(3)遍历 List //list.foreach(println) //list1.foreach(println) //list3.foreach(println) //list4.foreach(println) list5.foreach(println) } }
// 不可变的List集合 数据不允许被修改 private val ls1 = List("SCALA", "HDP", "SPARK" , 12 , 34) // 向Nil空队列中添加元素组成新的队列 val ls2 = "HIVE" :: "MYSQL" :: "HBASE" :: Nil // Nil 和 List.empty[Nothing]是等价的 private val ll = List.empty[Nothing] ls1(0) // 获取指定位置元素 // 添加一个元素生成新的List val ls3 = ls1 :+ "PYTHON" //合并两个集合 生成新的集合 val ls4 = ls1 ++ ls2 ls1.foreach(println) // 获取前两个元素 组成新的List ls1.take(2) println(ls1.take(2)) println(ls1.takeRight(2)) // 从右边取数据 // 遍历每个元素 参数是一个偏函数 ls1.collect({ case x: Int => x }) // 查找匹配的元素 仅仅返回一个元素 ls1.find(x=>x.toString.startsWith("S")) // 判断是否为null集合 ls1.isEmpty // 转换成可变List集合 ls1.toBuffer |
7.3.4可变List-->ListBuffer
说明:
(1)创建一个可变集合 ListBuffer (2)向集合中添加数据 (3)打印集合数据 |
代码实现:
Scala import scala.collection.mutable.ListBuffer object TestList { def main(args: Array[String]): Unit = { //(1)创建一个可变集合 val buffer = ListBuffer(1,2,3,4) //(2)向集合中添加数据 buffer.+=(5) buffer.append(6) buffer.insert(1,2) //(3)打印集合数据 buffer.foreach(println) //(4)修改数据 buffer(1) = 6 buffer.update(1,7) //(5)删除数据 buffer.-(5) buffer.-=(5) buffer.remove(5) } } |
7.4set
Set和list的最大区别在于Set中不可以存储重复数据 ,通常使用Set来实现元素的去重!!
Set集合也分为可变Set和不可变的Set,使用包名来区分可变和不可变,需要引用scala.collection.mutable.Set 包
7.4.1不可变set
说明:
(1)Set 默认是不可变集合,数据无序 (2)数据不可重复 (3)遍历集合 |
代码示例:
Scala object TestSet { def main(args: Array[String]): Unit = { //(1)Set 默认是不可变集合,数据无序 val set = Set(1,2,3,4,5,6) //(2)数据不可重复 val set1 = Set(1,2,3,4,5,6,3) //(3)遍历集合 for(x<-set1){ println(x) } } } |
7.4.2可变mutable.Set
说明:
(1)创建可变集合 mutable.Set (2)打印集合 (3)集合添加元素 (4)向集合中添加元素,返回一个新的 Set (5)删除数据 |
代码示例:
Scala object TestSet { def main(args: Array[String]): Unit = { //(1)创建可变集合 val set = mutable.Set(1,2,3,4,5,6) //(3)集合添加元素 set += 8 //(4)向集合中添加元素,返回一个新的 Set val ints = set.+(9) println(ints) println("set2=" + set) //(5)删除数据 set-=(5) //(2)打印集合 set.foreach(println) println(set.mkString(",")) } } |
7.5Map映射
Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,同样分为可变Map和不可变Map , 使用包名来区分是可变Map还是不可变Map
7.5.1不可变Map
说明:
(1)创建不可变集合 Map (2)循环打印 (3)访问数据 (4)如果 key 不存在,返回 0 |
代码示例:
Scala object TestMap { def main(args: Array[String]): Unit = { // Map //(1)创建不可变集合 Map val map = Map( "a"->1, "b"->2, "c"->3 ) //(3)访问数据 for (elem <- map.keys) { // 使用 get 访问 map 集合的数据,会返回特殊类型 Option(选项): 有值(Some),无值(None) println(elem + "=" + map.get(elem).get) } //(4)如果 key 不存在,返回 0 println(map.get("d").getOrElse(0)) println(map.getOrElse("d", 0)) //(2)循环打印 map.foreach((kv)=>{println(kv)}) } } |
7.5.2可变 Map
说明
(1)创建可变集合 (2)打印集合 (3)向集合增加数据 (4)删除数据 (5)修改数据 |
代码示例:
Scala object TestMap { def main(args: Array[String]): Unit = { //(1)创建可变集合 val map = mutable.Map( "a"->1, "b"->2, "c"->3 ) //(3)向集合增加数据 map.+=("d"->4) // 将数值 4 添加到集合,并把集合中原值 1 返回 val maybeInt: Option[Int] = map.put("a", 4) println(maybeInt.getOrElse(0)) //(4)删除数据 map.-=("b", "c") //(5)修改数据 map.update("d",5) map("d") = 5 //(2)打印集合 map.foreach((kv)=>{println(kv)}) } } |
7.6元组
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组。
示例内容:
(1)声明元组的方式:(元素 1,元素 2,元素 3)
(2)访问元组
(3)Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶
代码实现:
Scala object TestTuple { def main(args: Array[String]): Unit = { //(1)声明元组的方式:(元素 1,元素 2,元素 3) val tuple: (Int, String, Boolean) = (40,"bobo",true) //(2)访问元组 //(2.1)通过元素的顺序进行访问,调用方式:_顺序号 println(tuple._1) println(tuple._2) println(tuple._3) //(2.2)通过索引访问数据 println(tuple.productElement(0)) //(2.3)通过迭代器访问数据 for (elem <- tuple.productIterator) { println(elem) } //(3)Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶 val map = Map("a"->1, "b"->2, "c"->3) val map1 = Map(("a",1), ("b",2), ("c",3)) map.foreach(tuple=>{println(tuple._1 + "=" + tuple._2)}) } } |
7.7Option
Option(选项)类型用来表示一个值是可选的(有值或无值)
Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None 。
Option 有两个子类别,一个是 Some,一个是 None,当他回传 Some 的时候,代表这个函式成功地给了你一个 String,而你可以通过 get() 这个函式拿到那个 String,如果他返回的是 None,则代表没有字符串可以给你。
代码示例:
Scala val myMap: Map[String, String] = Map("key1" -> "value") val value1: Option[String] = myMap.get("key1") val value2: Option[String] = myMap.get("key2") println(value1) // Some("value1") println(value2) // None |
复习:
Scala package com.doit.day01.day02
import scala.collection.mutable import scala.collection.parallel.immutable
object ListTest { def main(args: Array[String]): Unit = { //1.定义一个长度为10的int类型的数组,里面装10个整数 // val arr: Array[Int] = new Array[Int](10) // arr(0) = 1 // arr.update(0,1) //第二种遍历方式 val arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
//2.打印数组的长度 // println(arr.length)
//3.遍历数组 //方式1:for循环 // for (elem <- arr) {println(elem)} //方式二,foreach // arr.foreach(println) //4.查看数组中的元素,显示成1--2--3...这样的形式 // println(arr.mkString("--")) //5.找到数组中的最大值 // println(arr.max) //6.找到数组中的最小值 // println(arr.min) //数组中的第一个元素 // println(arr.head) //数组中的最后一个元素 // println(arr.last) //数组中除了第一个元素的后面所有的元素 // println(arr.tail.mkString(",")) //数组中的前三个元素和后三个元素 // println(arr.take(3).mkString(","))//前三个 // println(arr.takeRight(3).mkString(",")) //计算数组中大于4的个数 // println(arr.count(_ > 4)) //将不可变数组转换成可变数组 val buffer: mutable.Buffer[Int] = arr.toBuffer //在可变数组中添加一个元素10 // buffer.append(10) // buffer.+=(10) // buffer += 10 //在指定索引为1的位置插入11,12两个元素 // buffer.insert(1,11,12) //删除一个指定的元素元素 // buffer.-=(1) // buffer -= 1 //删除指定索引位置的元素 // buffer.remove(1) //数组的反转 // buffer.reverse
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7) // val list1: List[Int] = 1 :: 2 :: 3 :: 4 :: 5 :: Nil //遍历list // for (elem <- list) {} // list.foreach(println) list.head list.tail list.last list.max list.min list.take(2) // list ::: arr.toList 正常都用不到 //val ints: List[Int] = list.::(1) 加在最前面
// Set(1,2,2,6,3,4)
// val ints: mutable.Set[Int] = mutable.Set(1, 2, 3, 4, 5, 6, 7) // for (elem <- ints) {} //添加一个元素 // ints.+=(1) //删除索引位置的元素 // ints.remove(1) //删除指定的元素 // ints.-=(1)
// val map: Map[String, Int] = Map("hadoop" -> 1, "hive" -> 2, "hbase" -> 3) // val tail: Map[String, Int] = map.tail // val head: (String, Int) = map.head // val i: Int = map.getOrElse("hadoop", 0) // map.get("he").get //用这个的时候得注意报错,正常情况下用getOrElse
val map: mutable.Map[String, Int] = mutable.Map("hadoop" -> 1, "hive" -> 2, "hbase" -> 3) // map.update("hadoop", 111) // map.+=("he"->11) // map.put("haha",11 ) // map.remove("hadoop") // for (elem <- map) {}
// for (elem <- map) {} // val tuple = (1,"sy",false,1.0) // val tuple2: (Int, String) = Tuple2(1, "hh") } } |
7.8集合中的常用方法
7.8.1forEach
迭代遍历集合中的每个元素,对每个元素进行处理 ,但是没有返回值 ,常用于打印结果数据 !
Scala val ls = List(1,3,5,7,9) ls.foreach(println) // 打印每个元素 ls.foreach(println(_))// 打印每个元素 ls.foreach(x=>println(x*10)) // 每个元素乘以10 打印结果 ls.foreach(x=>print(x+" "))// 打印每个元素 空格隔开 |
7.8.2map
适用于任意集合
注意Map集合的用法:map函数遍历每个元素处理返回原集合类型的新集合 , 也可以不返回数据列表,数组,Map中都有map函数 元组中没有map函数
Scala val arr = Array[String]("JAVA", "C++", "SCALA") val ls = List(1, 3, 5, 7, 9) val set = Set(1, 3, 5, 7) val mp = Map[String, Int]("ZSS" -> 100, "LSS" -> 99) // map函数遍历每个元素处理返回原集合类型的新集合 val new_arr: Array[String] = arr.map(x => x) val new_list: List[Int] = ls.map(x => x) val new_set: Set[Int] = set.map(x => x) // Map集合使用map函数 val new_Map1: Map[String, Int] = mp.map({ case v: (String, Int) => (v._1, v._2 * 10) }) val new_Map2: Map[String, Int] = mp.map(e => (e._1, e._2 + 100)) // map函数也可以不返回数据 ls.map(println(_)) |
7.8.3filter和filterNot
适用于: 数组 List Map
filter返回符合自己条件的新的集合,filterNot返回不符合自己条件的新的集合
Scala val ls: List[Int] = List.range(1,10) ls.filter(x=>x%2==0) val new_list: List[Int] = ls.filter(_ % 2 == 0)// _ 代表每个元素 new_list .foreach(x=>print(x+" ")) // 2 4 6 8 ls.filterNot(_%2!=1).foreach(x=>print(x+" ")) 1 3 5 7 9 |
每个元素进行过滤
Scala val set = Set("spark" , "scala" , "c++" , "java") val new_set: Set[String] = set.filter(_.startsWith("s")) set.filter(_.length>3) |
多条件filter进行条件过滤
Scala val ls = "spark":: "scala" :: "c++"::"java"::1::2::12.34::Nil // 过滤出String类型的和Double类型的数据 ls.filter{ case i:String => true case i:Int=>false case i:Double=>true } |
连续使用多次filter进行条件过滤
Scala // 连续使用多次filter进行条件过滤 val map = Map[String,Int](("zss" ,91),("zww",89),("zzx",92) , ("ww",23)) map.filter(_._1.startsWith("z")).filter(_._2>90) |
7.8.4collect
常用于: Array List Map
collect函数也可以遍历集合中的每个元素处理返回新的集合
def map[B](f: (A) ⇒ B): List[B] def collect[B](pf: PartialFunction[A, B]): List[B] |
主要支持偏函数
Scala val ls = List(1,2,3,4,"hello") // 主要支持偏函数 val new_list: List[Int] = ls.collect({case i:Int=>i*10}) new_list.foreach(x=>print(x+" "))//10 20 30 40 // collect实现filter和map特性 list.collect({ case i: Int => i * 10 case i: String => i.toUpperCase }).foreach(println) val new_list2: List[Int] = ls.map({case x:Int=>x*10}) new_list2.foreach(x=>print(x+" "))// 错误 hello (of class java.lang.String) |
因为collect支持偏函数 , 所以我们可以使用collect实现filter和map的特性!!!
Scala val res: List[Int] = List(1, 2, 3, 4, 5, 6,"hello").collect({case i:Int if i%2==0=>i*10}) res.foreach(println) // 40 60 是不是牛逼闪电?? |
7.8.5min和max
适用于:数组 List Map
Scala val arr = Array(1,2,345,67,5) arr.min arr.max arr.sum |
Scala val ls = List(1,2,345,67,5) ls.min ls.max ls.sum |
Scala val set = Set(1,2,345,67,5) set.min set.max set.sum |
Scala val map = Map[String,Int]("a"->10, "b"->99 , "c"->88) // map默认按照key排序获取最大和最小数据 map.min //(a,10) map.max //(c,88) |
7.8.6minBy和maxBy
适用于: 数组 List Map
集合中的min和max可以获取任意集合中的最小和最大值 ,但是如果集合中存储的是用户自定义的类 , 或者是按照Map集合中的key, value规则排序的话就需要用户指定排序规则
Scala val map = Map[String,Int]("a"->10, "b"->99 , "c"->88) // map默认按照key排序获取最大和最小数据 // 指定map排序 按照value排序 map.maxBy(x=>x._2) //(b,99) map.minBy(x=>x._2) //(a,10) |
Scala class User(val name:String ,val age:Int) {} |
方式一 隐式转换
Scala implicit def ordersUser(user:User)={ new Ordered[User] { override def compare(that: User) = { user.age.compareTo(that.age) } } } val ls = List(new User("zs",22),new User("ww",18) ,new User("tq",34)) println(ls.max.name) println(ls.min.name) |
Scala println(ls.maxBy(x => x.age).name) |
方式二:
7.8.7sum
适用于 数组 List Set
求集合中的所有元素的和 ,下面三种集合类型常用
Scala val arr = Array(1,2,345,67,5) arr.sum
val ls = List(1,2,345,67,5) ls.sum
val set = Set(1,2,345,67,5) set.sum |
7.8.8count
适用于 数组 List Map
def count(p: ((A, B)) => Boolean): Int
计算满足指定条件的集合元素数量
Scala val arr = Array(1,2,345,67,5) arr.count(_>5) // array list set 统用
val ls = List("hello" , "hi" , "heihei" , "tom") ls.count(_.startsWith("h")) ls.count(_.equals("hello")) ls.count(_ == "hello") // 忽略大小写 ls.count(_.equalsIgnoreCase("HELLO")) // 统计符合条件的map元素的数量 val map = Map[String,Int]("a"->10,"ab"->10, "b"->99 , "c"->88) map.count(x=>x._1.startsWith("a")) map.count(_._2>10) |
7.8.9find
适用于 数组 List Map
查找符合要求的元素 , 匹配到就反回数据 ,最多只返回一个
Option中的数据要么是Some(T) 要么是None标识没有找到
Scala val arr = Array(1,2,345,67,5) val e: Option[Int] = arr.find(x=>x>1)
val ls = List("hello" , "hi" , "heihei" , "tom") val res: Option[String] = ls.find(_.contains("a")) if(res.isDefined){ println(res) //Some(hello) println(res.get) //hello } val map = Map[String,Int]("a"->10,"ab"->10, "b"->99 , "c"->88) val res_map: Option[(String, Int)] = map.find(x=>x._2>20) if(res_map.isEmpty){ "没有匹配到内容" }else{ // 打印数据 println(res_map.get) } |
7.8.10flatten
适用于 数组 List
压平 将一个集合展开 组成一个新的集合
Scala val arr = Array(1,2,345,67,5.23) //val res1: Array[Nothing] = arr.flatten I数值了类型的无法压平 val ls = List("hello" , "hi" , "heihei" , "tom") val res2: Seq[Char] = ls.flatten // 压成单个字符 因为字符串属于序列集合的一种 val map = Map[String,Int]("a"->10,"ab"->10, "b"->99 , "c"->88) // map无法直接压平 //val flatten: immutable.Iterable[Nothing] = map.flatten // 压平存储Map集合的list 获取Map中每个元素 val ls1 = List[Map[String,Int]](Map[String,Int]("a"->10,"ab"->10) , Map[String,Int]("jim"->100,"cat"->99)) ls1.flatten // List((a,10), (ab,10), (jim,100), (cat,99))
val res: List[Int] = List(Array(1,2,3),Array(4,5,6)).flatten // 错误 注意压平的数据的类型 val res4 = List(Array(1,2,3),Array("hel",5,6)).flatten |
7.8.11flatMap
适用于 数组 List
map+flatten方法的组合 ,先遍历集合中的每个元素 , 再按照指定的规则压平, 返回压平后的新的集合
Scala val ls = List("today is my first day of my life" , "so I feel so happy") // map处理每个元素 就是处理每句话 ls.map(x=>println(x)) // 获取集合中的每个元素 获取两句话 然后再扁平成字符 ls.flatMap(x=>x) // 指定扁平化的规则 按照空格压平 压平的规则 ls.flatMap(x=>x.split(" ")).foreach(println) // 获取到每个单词
// 读取外部文件 val bs: BufferedSource = Source.fromFile("d://word.txt") // 读取所有的数据行 val lines: Iterator[String] = bs.getLines() // m遍历每行数据按照 \\s+ 切割返回一个新的迭代器 val words: Iterator[String] = lines.flatMap(_.split("\\s+")) // 遍历迭代器 获取每个单词 words.foreach(println) // 读取外部文件 val bs2: BufferedSource = Source.fromFile("d://word.txt") // 获取所有的行数据 val lines2: Iterator[String] = bs2.getLines() // 处理每行数据 切割单词后 每行返回一个数组 将所有的数组封装在迭代器中 val arrs: Iterator[Array[String]] = lines2.map(_.split("\\s+")) |
7.8.12 mapValues
适用于 Map
mapValues方法只对Map集合的value做处理!
7.8.13sorted
适用于 数组 List Map
sorted 使用域简单的数字, 字符串等排序规则简答的集合进行排序 , 如果需要定制化排序建议使用sortBy 和 sortWith函数
List对数值
Scala val list = List (1, 34 , 32 , 12 , 20 ,44 ,27) // 返回排好序的list集合 默认从小到达排序 val sorted: List[Int] = list.sorted |
对Array字符串
Scala val arr = Array("jim" , "cat" , "jong" , "huba") // 字符串默认按照先后排序 val sorted_arr: Array[String] = arr.sorted |
对map
Scala val map = Map[String , Int]("aeiqi"->4 , "qiaozhi"->2 , "baji"->34) // map集合也没有sorted 函数 只有转换成List或者Array集合 默认按照key字典先后排序 val sorted_map: Seq[(String, Int)] = map.toList.sorted sorted_map.foreach(println) |
7.8.14sortBy和sortWith
适用于 数组 List Map
Scala var arr = Array(1, 11, 23, 45, 8, 56) val arr1 = arr.sortBy(x => x) //ArraySeq(1, 8, 11, 23, 45, 56) //按照数据倒序排列 val arr2 = arr.sortBy(x => -x) //(56, 45, 23, 11, 8, 1) // 按照字典顺序排序 val arr3 = arr.sortBy(x => x.toString) //ArraySeq(1, 11, 23, 45, 56, 8) // x 前面的元素 y 后面的元素 arr.sortWith((x, y) => x > y) arr.sortWith((x, y) => x < y)
var list = List("hello", "cat", "happy", "feel") // 字典顺序 list.sortBy(x => x) // 执行排序 list.sortWith((x, y) => x > y) list.sortWith((x, y) => x < y)
val map = Map("peiqi" -> 5, "jong" -> 3, "baji" -> 12) map.toList.sortBy(x => x._1) //List((baji,12), (jong,3), (peiqi,5)) map.toList.sortBy(x => x._2) //List((jong,3), (peiqi,5), (baji,12)) // 指定key排序 map.toArray.sortWith((x,y)=>x._1>y._1) map.toArray.sortWith((x,y)=>x._1<y._1) //指定value排序规则 map.toArray.sortWith((x,y)=>x._2>y._2) map.toArray.sortWith((x,y)=>x._2<y._2) |
自定义类型在集合中的排序
Scala val u1 = new User("wuji", 34) val u2 = new User("zhiruo", 24) val u3 = new User("zhoamin", 44) val u4 = new User("cuishan", 64)
var arr = Array(u1, u2, u3, u4) // 按照姓名字典排序 arr.sortBy(user => user.name) //年龄小到大 arr.sortBy(user => user.age) //数值类型的排序可以直接使用- 来倒序排列 年龄大到小 arr.sortBy(user => -user.age) // 年龄大到小 arr.sortWith((user1, user2) => user1.age > user2.age) // 年龄小到大 arr.sortWith((user1, user2) => user1.age < user2.age) // 姓名字典升序 arr.sortWith((user1, user2) => user1.name < user2.name) //姓名字典降序 arr.sortWith((user1, user2) => user1.name > user2.name) |
7.8.15partition和span (了解)
partition将数组按照指定的规则分组 ,适用于 数组 List Map
Scala val list = List(1,2,3,4,5,6,7,8,9) // 将集合根据条件分成两组返回一个存储集合的元组第一个集和实符合要求的元素 //(List(3, 6, 9),List(1, 2, 4, 5, 7, 8)) val res: (List[Int], List[Int]) = list.partition(x=>x%3==0) //从第一个元素开始处理 配到不符合条件的就结束 list.span(_<3) // (List(1, 2),List(3, 4, 5, 6, 7, 8, 9))
val list2 = List("scala" , "is" , "option" , "fucntion") // (List(scala, is, fucntion),List(option)) list2.partition(_.hashCode%2==0) map集合****************************************** val map = Map("peiqi" -> 5, "jong" -> 3, "baji" -> 12) // (Map(baji -> 12),Map(peiqi -> 5, jong -> 3)) val tuple: (Map[String, Int], Map[String, Int]) = map.partition(x=>x._1.contains("b")) val tuple2: (Map[String, Int], Map[String, Int]) = map.partition(x=>x._2 >5) |
7.8.16grouped
将集合中的元素按照指定的个数进行分组
Scala val list1 = List(1,2,3,4,5,6,7,8,9) val list2 = List("scala" , "is" , "option" , "fucntion") val map = Map[String,Int]("peiqi" -> 5, "jong" -> 3, "baji" -> 12) // 两个元素分成一组 ,9个元素总共分成5组 val res: Iterator[List[Int]] = list1.grouped(2) var i = 0 // 遍历每个元素 res.foreach(list=>{ i+=1 list.foreach(x=>println(x+"----"+i)) // 打印每个元素和它所对应的组 }) // 将map集合按照个数进行分组 val res2: Iterator[Map[String, Int]] = map.grouped(2) res2.foreach(i=>i.foreach(x=>println((x._1,x._2)))) |
7.8.17groupBy
将集合中的数据按照指定的规则进行分组
序列集合
Scala val list1 = List(1,2,3,4,5,6,7,8,9) val list2 = List("scala" , "is" , "option" , "fucntion") // 对序列数据进行分组 val res1: Map[Boolean, List[Int]] = list1.groupBy(x=>x>3) //HashMap(false -> List(1, 2, 3), true -> List(4, 5, 6, 7, 8, 9)) val res2: Map[Boolean, List[Int]] = list1.groupBy(x=>x%2==0)//HashMap(false -> List(1, 3, 5, 7, 9), true -> List(2, 4, 6, 8)) list2.groupBy(x=>x.hashCode%2==0) //HashMap(false -> List(is, option, fucntion), true -> List(scala)) val res: Map[Boolean, List[String]] = list2.groupBy(x=>x.startsWith("s")) |
键值映射集合分组
Scala val map = Map[String,Int]("peiqi" -> 5, "jong" -> 3, "baji" -> 12) val arr = Array(("cat",21),("lucy",33),("book",22),("jack",34)) // 按照key和value的内容分组 println(map.groupBy(mp => mp._1)) println(map.groupBy(mp => mp._2)) // 根据key 或者 value 分成两组 满足条件的和不满足条件的 println(map.groupBy(mp => mp._1.hashCode%2==0)) println(map.groupBy(mp => mp._2>2))
// 对偶元组集合 和map的分组方式是一样的 arr.groupBy(arr=>arr._1) arr.groupBy(arr=>arr._2) |
7.8.18reduce
底层调用的是reduceLeft , 从左边开始运算元素
Scala val list = List(1,3,5,7,9) // 每个元素累加 从左到右相加 val res1: Int = list.reduce(_+_) // 25 //1-3)-5)-7)-9 val res2: Int = list.reduce(_ - _) // -23 val arr = Array("haha", "heihei", "hehe") // x 前面的元素 y 后面的元素 实现集合中字符串的拼接 val res3: String = arr.reduce((x, y) => x + " " + y) //haha heihei hehe // 键值对元素的 val map = Map(("shaolin",88),("emei", 77),("wudang",99)) //(shaolin emei wudang,264) key value分别做归约操作 val res4: (String, Int) = map.reduce((m1,m2)=>(m1._1+" "+m2._1 , m1._2+ m2._2)) |
7.8.19reduceLeft和reduceRight
Scala val list = List(1, 3, 5, 7, 9) val arr = Array("a", "b", "c","d","e") val map = Map(("shaolin",88),("emei", 77),("wudang",99)) // 执行顺序是 1+3)+5)+7)+9 val res1: Int = list.reduceLeft(_+_) // 1-3)-5)-7)-9 val res01: Int = list.reduceLeft(_-_) val res2: String = arr.reduceLeft((a1, a2)=>a1+","+a2) val res3: (String, Int) = map.reduceLeft((m1,m2)=>(m1._1+" "+m2._1 , m1._2+ m2._2)) println(res1) //25 println(res2) //a,b,c,d,e println(res3)//(shaolin emei wudang,264)
val res11: Int = list.reduceRight(_+_) // 25 // 执行顺序是 a,(b,(c,(d,e))) a2 右边的最后一个元素 val res12: String = arr.reduceRight((a1, a2)=>a1+","+a2)//a,b,c,d,e val res13: (String, Int) = map.reduceRight((m1,m2)=>(m1._1+" "+m2._1 , m1._2+ m2._2))//(shaolin emei wudang,264) // 5-(7-9)-->5-(7-9)-->3-(5-(7-9))-->1-(3-(5-(7-9))) val res14: Int = list.reduceRight(_-_) println(res14) // 5 println(res11) //25 println(res12) //a,b,c,d,e println(res13)//(shaolin emei wudang,264) // 字符串的拼接 arr.reduce(_ ++ _) // 字符串的拼接 println(arr.reduce(_ ++"."++ _)) |
7.8.20fold,foldLeft 和foldRight
归约操作类似于reduce函数 ,但是fold函数中多出来一个初始值
Scala val arr = Array("tom" , "cat" , "jim" , "rose") // 遍历集合中的每个元素进行拼接 比reduce函数多出一个初始值 val res = arr.fold("hello")(_+" "+_) val ls = List(1,3,5,7) // 100+1)+3)+5)+7 底层调用的是 foldLeft val res2 = ls.fold(100)(_+_) // 116 ls.foldLeft(100)(_+_) // 116 从右边开始运算 默认的值先参与运算进来 // 7-10)-->5-(-3)-->3-8 -->1-(-5) val res01: Int = ls.foldRight(10)(_-_) //6 |
7.8.21交集差集并集
Scala val arr1 = Array(1, 3, 5, 7, 0) val arr2 = Array(5, 7, 8, 9) val res1: Array[Int] = arr1.intersect(arr2) // 交集 5 7 val res2: Array[Int] = arr1.diff(arr2) // 差集 1 3 // 单纯的合并两个元素中的数据 val res3: mutable.ArraySeq[Int] = arr1.union(arr2) // 1,3,5,7 ,5,7,8,9 // 去除重复数据 val res4: mutable.ArraySeq[Int] = res3.distinct //,3,5,7,8,9 |
7.8.22distinct和distinctBy
去除集合中的重复的元素 ,可以去除简单类型的数据, 也可以除去自定义的类型(底层依然是hashcode和equals)
Scala val arr1 = Array("a", "a","ab","cat" ,"hellocat" ,"hicat") val newarr: Array[String] = arr1.distinct newarr.foreach(println) |
条件去重
Scala val arr1 = Array(new User("ls",21),new User("ls",22),new User("zss",21)) // 去除重名的重复数据 val res: Array[User] = arr1.distinctBy(x=>x.age) res.foreach(x=> println(x.name)) |
7.8.23zip
实现拉链式拼接, 只要操作的集合是迭代集合就可以拼接
Scala val list1 = List("a" , "b" , "c" , "d") val arr1 = Array(1,2,3,4) val map = Map[String,Int]("aa"->11,"cc"->22,"dd"->33) // 以两个迭代集合中少的一方为基准对偶拼接List((a,1), (b,2), (c,3)) val res: List[(String, Int)] = list1.zip(arr1) //ArraySeq((1,(aa,11)), (2,(cc,22)), (3,(dd,33))) val res2: Array[(Int, (String, Int))] = arr1.zip(map) |
7.8.24zipWithIndex
简单理解为 遍历集合中的每个元素 , 将每个元素打上对应的索引值 , 组成元组(element , index) 返回新的集合 !
Scala val list1 = List("a" , "b" , "c" , "d") val arr1 = Array(1,2,3,4) val map = Map[String,Int]("aa"->11,"cc"->22,"dd"->33) // List(((a,1),0), ((b,2),1), ((c,3),2), ((d,4),3)) list1.zip(arr1).zipWithIndex //List((a,0), (b,1), (c,2), (d,3)) list1.zipWithIndex |
7.8.25scan
一个初始值开始,从左向右遍历每个元素,进行积累的op操作
Scala val arr = Array("cat" , "jim" , "tom") // ArraySeq(hello, hello cat, hello cat jim, hello cat jim tom) arr.scan("hello" )(_ +" "+ _) val nums = List(1,2,3) // List(10,10+1,10+1+2,10+1+2+3) = List(10,11,13,16) val result = nums.scan(10)(_+_) nums.foldLeft(10)(_+_) // 16 |
7.8.26mkString
将集合中的每个元素拼接成字符串
Scala val arr = Array("a", "b", "c") val str = arr.mkString arr.mkString(" ") arr.reduce(_+_) arr.reduce(_ + " " + _) |
7.8.27slice,sliding
slice(from: Int, until: Int): List[A] 提取列表中从位置from到位置until(不含该位置)的元素列表, 起始位置角标从0开始;
Scala val arr = Array("a", "b", "c" ,"d","e","f") arr.slice(0 ,2) // res0: Array[String] = ArraySeq(a, b) |
sliding(size: Int, step: Int): Iterator[List[A]] 将列表按照固定大小size进行分组,步进为step,step默认为1,返回结果为迭代器;
Scala val nums = List(1,1,2,2,3,3,4,4) // 参数一:子集的大小 参数二:步进 val res: Iterator[List[Int]] = nums.sliding(2,2) res.toList // List(List(1, 1), List(2, 2), List(3, 3), List(4, 4)) |
7.8.28take,takeRight,takeWhile
Scala val arr = Array("a", "b", "c" ,"d","e","f") // 从左边获取三个元素,组成新的数组集合 arr.take(3) |
Scala val nums = List(1,1,1,1,4,4,4,4) val right = nums.takeRight(4) // List(4,4,4,4) |
Scala // 小于4 终止 nums.takeWhile(_ < 4) val names = Array ("cat", "com","jim" , "scala" ,"spark") // 从左到右遍历符合遇到不符合条件的终止,储存在新的集合中 names.takeWhile(_.startsWith("c")) |
7.8.29Aggregate聚合
全局聚合
aggregate方法是一个聚合函数,接受多个输入,并按照一定的规则运算以后输出一个结果值,在2.13+版本中被foldLeft取代!
7.8.30集合间的转换函数
可变集合和不可变集合的转换
Scala的面向对象 ,构造器 , 代码块 , 集合 以及集合的常用方法.