I . List 集合高阶函数引入



1 . 高阶函数 : 函数的 参数 或 返回值类型 是 函数类型 的 函数 , 是高阶函数 ;


2 . List 集合中定义的高阶函数 : List 集合中使用了大量的高阶函数 , 如 maxBy , filter , map , any , count , find , groupBy 等函数 , 这些函数的参数都是 函数类型的 , 需要传入一个函数类型实例作为其参数 ;



II . Kotlin 数据类 ( data class )



1 . 数据类介绍 : Kotlin 中 data class 类能快速帮助开发者封装 各种类型的数据 , 编译后生成的 JavaBean 只生成最基本的几个函数 , 如 hashCode() , toString() , copy() 等 ;


2 . 数据类型 ( data class ) 定义 :


① 参数格式 : 定义数据类时需要将要封装的字段写在构造函数中 , 格式如下 :

var / val 变量名 : 变量类型

② 参数要求 : 构造函数必有 >= 1 个参数 , 参数格式必须按照上述格式声明 ;

③ 修饰 : data class 不能被 abstract / inner / open / sealed 修饰 ;

④ 继承关系 : data class 可以实现接口 , 在 1.1 版本后 , 可以继承 ;


3 . Kotlin 数据类 功能 :


① 变量相关 : 自动生成成员变量 , 及对应的 getter 和 setter 方法 ;

③ 基本方法 : 自动生成 equals() , hashCode() , toString() , componentN() , copy() 等方法 ;


4 . Kotlin 数据类 实例 :

data class Student(var name : String, var age : Int, var height : Int)

5 . JavaBean 参考 : 上面定义的 Kotlin 数据类 , 与下面的 JavaBean 基本一致 , 实现的那一串方法就算了 ;

public class Student {

    private String name;

    private int age;

    private int height;

    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;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}


这个数据类节省了很多行代码 ;



III . Java 代码 与 Kotlin 代码实现对比 ( 查询年龄最大的 )



1 . 声明 List 集合 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

2 . 按照 Java 代码的逻辑实现找找年龄最大的学生 : 先找出最大年龄 , 然后遍历找出最大年龄的学生 ;

/**
 * 筛选出 students 中 18 岁的学生 , 并打印出来
 *
 * 这是按照 Java 代码的逻辑写的
 */
fun filterByAge(age : Int){

    // 1 . 先创建一个集合
    var filterStudents : ArrayList<Student> = ArrayList<Student>()

    // 2 . 遍历 students 集合 , 并将 18 岁的筛选出来
    for (student in students){
        if(student.age == age){
            filterStudents.add(student);
        }
    }

    // 3 . 打印筛选出的学生
    for(student in filterStudents){
        println("${student.name} , ${student.age} , ${student.height}")
    }

}

3 . 使用 maxBy 高阶函数实现同样的功能 : 代码要比上面精简很多 , 因此在 Kotlin 中使用高阶函数 , 能极大提高开发效率 ;

// 获取年龄最大的学生
var maxAgeStudent = students.maxBy { it.age }
println(maxAgeStudent)


IV . maxBy 高阶函数



maxBy 函数原型 : 获取集合中某个元素的某个字段最大值的元素 , 如果有多个最大值元素 , 那么返回第一个 ;

/**
 * Returns the first element yielding the largest value of the given function or `null` if there are no elements.
 * 
 * @sample samples.collections.Collections.Aggregates.maxBy
 */
public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? {
    val iterator = iterator()
    if (!iterator.hasNext()) return null
    var maxElem = iterator.next()
    if (!iterator.hasNext()) return maxElem
    var maxValue = selector(maxElem)
    do {
        val e = iterator.next()
        val v = selector(e)
        if (maxValue < v) {
            maxElem = e
            maxValue = v
        }
    } while (iterator.hasNext())
    return maxElem
}

2 . maxBy 函数的几个要素 :

Iterable<T>.maxBy(selector: (T) -> R): T?

① 函数调用者 : maxBy 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : selector: (T) -> R 是函数参数 ;

③ 函数返回值 : 返回值是 T? 类型 , 后面的 ? 表示返回值不为空 ; T 类型是一个泛型 , 是集合中元素的类型 ;


3 . maxBy 参数解析 : selector: (T) -> R , 这是一个函数类型参数 ; selector 是 选择器 含义 ;


① selector : 函数类型变量名 ;

② (T) -> R 是函数参数类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 R 类型 , 表示 T 类型的某个字段 ;


4 . maxBy 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 selector: (T) -> R , 该函数类型变量通过 selector(T) 进行调用 , 在 maxBy 中通过该函数类型变量 , 调用该变量对应的函数 , 实现了获取 T 对象某个字段最大值元素的功能 ;


5 . maxBy 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

// 获取年龄最大的学生
var maxAgeStudent = students.maxBy { it.age }
println(maxAgeStudent)

② 执行结果 :

Student(name=Jack, age=29, height=165)


V . minBy 高阶函数



minBy 与 maxBy 基本类似 , maxBy 是获取元素某字段最大值的第一个元素 , minBy 是获取元素某字段最小值的第一个元素


minBy 函数原型 : 获取集合中某个元素的某个字段最小值的元素 , 如果有多个最小值元素 , 那么返回第一个 ;

/**
 * Returns the first element yielding the smallest value of the given function or `null` if there are no elements.
 * 
 * @sample samples.collections.Collections.Aggregates.minBy
 */
public inline fun <T, R : Comparable<R>> Iterable<T>.minBy(selector: (T) -> R): T? {
    val iterator = iterator()
    if (!iterator.hasNext()) return null
    var minElem = iterator.next()
    if (!iterator.hasNext()) return minElem
    var minValue = selector(minElem)
    do {
        val e = iterator.next()
        val v = selector(e)
        if (minValue > v) {
            minElem = e
            minValue = v
        }
    } while (iterator.hasNext())
    return minElem
}

2 . minBy 函数的几个要素 :

Iterable<T>.minBy(selector: (T) -> R): T?

① 函数调用者 : minBy 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : selector: (T) -> R 是函数参数 ;

③ 函数返回值 : 返回值是 T? 类型 , 后面的 ? 表示返回值不为空 ; T 类型是一个泛型 , 是集合中元素的类型 ;


3 . minBy 参数解析 : selector: (T) -> R , 这是一个函数类型参数 ; selector 是 选择器 含义 ;


① selector : 函数类型变量名 ;

② (T) -> R 是函数参数类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 R 类型 , 表示 T 类型的某个字段 ;


4 . minBy 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 selector: (T) -> R , 该函数类型变量通过 selector(T) 进行调用 , 在 minBy 中通过该函数类型变量 , 调用该变量对应的函数 , 实现了获取 T 对象某个字段最小值元素的功能 ;


5 . minBy 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

// 获取身高最低的学生
var minHeightStudent = students.minBy { it.height }
println(minHeightStudent)

② 执行结果 :

Student(name=Jerry, age=18, height=165)


VI . filter 高阶函数



filter 函数原型 : 返回 List 集合 , 该集合中的元素全部符合传入的 predicate: (T) -> Boolean 类型函数要求 , 即执行该 (T) -> Boolean 类型函数 , 传入 T 元素对象 , 返回值为 true ; 传入一个函数 , 该函数判定集合中的每个元素是否符合某种要求 ;

/**
 * Returns a list containing only elements matching the given [predicate].
 */
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

2 . filter 函数的几个要素 :

Iterable<T>.filter(predicate: (T) -> Boolean): List<T>

① 函数调用者 : filter 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : predicate: (T) -> Boolean 是函数参数 ;

③ 函数返回值 : 返回值是 List 类型 , 是一个 泛型为 T 类型的 List 集合 ;


3 . filter 参数解析 : predicate: (T) -> Boolean , 这是一个函数类型参数 ; predicate 是 谓词 含义;


① predicate : 函数类型变量名 ;

② (T) -> Boolean 是函数参数的类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 Boolean 类型 , 表示 T 类型是否符合某种要求 , 符合该要求才会将该元素放到 filter 方法返回值集合中 ;


4 . filter 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 predicate: (T) -> Boolean , 该函数类型变量通过 predicate(T) 进行调用 , 执行该函数返回 true 的元素 , 会被放到 filter 方法返回值集合中 ;


5 . filter 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

// 筛选出年龄大于 15 , 并且身高小于 180 的学生 , 其返回值是一个集合
//  后面可以有多个 and 连接多个判断语句
var ageH15HeightLow180 = students.filter {
    (it.age > 15 ) and (it.height < 180)
}
println(ageH15HeightLow180)

② 执行结果 :

[Student(name=Jerry, age=18, height=165), Student(name=Trump, age=18, height=178), Student(name=Jack, age=29, height=165)]


VII . map 高阶函数



map 函数原型 : 返回 List<R> 集合 , 该集合中的元素的类型是一个生成的新类型 , 该类型是根据原来的集合 List<T> 元素进行转换映射成的新类型 ; 传入一个函数 , 该函数将集合中的每个元素进行某种转换 , 产生一个新类型元素 ;

/**
 * Returns a list containing the results of applying the given [transform] function
 * to each element in the original collection.
 * 
 * @sample samples.collections.Collections.Transformations.map
 */
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

2 . map 函数的几个要素 :

Iterable<T>.map(transform: (T) -> R): List<R>

① 函数调用者 : map 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : transform: (T) -> R 是函数参数 ;

③ 函数返回值 : 返回值是 List 类型 , 是一个 泛型为 R 类型的 List 集合 ; 该 R 类型是生成的新类型 ;


3 . map 参数解析 : transform: (T) -> R , 这是一个函数类型参数 ; transform 有 转换变换 含义;


① transform : 函数类型变量名 ;

② (T) -> R 是函数参数的类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 R 类型 , 将 T 类型元素转换成 R 类型 ;


4 . map 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 transform: (T) -> R , 该函数类型变量通过 transform(T) 进行调用 , 执行该函数返回 R 类型元素 , map 的返回值就是这些 R 类型元素的 List<R> 集合 ;


5 . map 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

//将 Student 对象中的 姓名 和 年龄抽取出来 , 拼接成 "姓名 : 年龄" 字符串, 放到一个新的 字符串集合中
var studentNameAgess = students.map {
    "${it.name} : ${it.age}"
}
println(studentNameAgess)

② 执行结果 :

[Tom : 12, Jerry : 18, Trump : 18, Jack : 29]


VIII . any 高阶函数



any 函数原型 : 返回该集合中是否存在某个元素 ; 传入一个函数 , 该函数判定集合中的每个元素是否符合某种要求 ;

/**
 * Returns `true` if at least one element matches the given [predicate].
 * 
 * @sample samples.collections.Collections.Aggregates.anyWithPredicate
 */
public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
    if (this is Collection && isEmpty()) return false
    for (element in this) if (predicate(element)) return true
    return false
}

2 . any 函数的几个要素 :

Iterable<T>.any(predicate: (T) -> Boolean): Boolean

① 函数调用者 : any 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : predicate: (T) -> Boolean 是函数参数 ;

③ 函数返回值 : 返回值是 Boolean 类型 , 该集合中如果存在符合某种条件的元素 , 返回 true , 否则返回 false ;


3 . any 函数类型参数解析 : predicate: (T) -> Boolean , 这是一个函数类型参数 ; predicate有 谓词 含义;


① predicate: 函数类型变量名 ;

② (T) -> Boolean 是函数参数的类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 Boolean 类型 , 函数的执行内容 : 如果 T 类型参数符合函数中的要求 , 返回 true , 反之返回 false ;


4 . any 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 predicate: (T) -> Boolean , 该函数类型变量通过 predicate(T) 进行调用 , 执行该函数返回 Boolean 值 , 表示该 T 类型对象是否符合函数中的要求 ;


5 . any 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

//集合中是否有 18 岁的学生
var is18AgeExist : Boolean = students.any{
    it.age == 18
}
println(is18AgeExist)

② 执行结果 :

true


IX . count 高阶函数



count 函数原型 : 返回该集合中符合给定谓词要求的元素个数 ; 传入一个函数 , 该函数用于判定元素是否符合要求;

/**
 * Returns the number of elements matching the given [predicate].
 */
public inline fun <T> Iterable<T>.count(predicate: (T) -> Boolean): Int {
    if (this is Collection && isEmpty()) return 0
    var count = 0
    for (element in this) if (predicate(element)) checkCountOverflow(++count)
    return count
}

2 . count 函数的几个要素 :

Iterable<T>.count(predicate: (T) -> Boolean): Int

① 函数调用者 : count 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : predicate: (T) -> Boolean 是函数参数 ;

③ 函数返回值 : 返回值是 Boolean 类型 , 该集合中如果存在符合某种条件的元素 , 返回 true , 否则返回 false ;


3 . count 函数类型参数解析 : predicate: (T) -> Boolean , 这是一个函数类型参数 ; predicate有 谓词 含义;


① predicate: 函数类型变量名 ;

② (T) -> Boolean 是函数参数的类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 Boolean 类型 , 函数的执行内容 : 如果 T 类型参数符合函数中的要求 , 返回 true , 反之返回 false ;


4 . count 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 predicate: (T) -> Boolean , 该函数类型变量通过 predicate(T) 进行调用 , 执行该函数返回 Boolean 值 , 表示该 T 类型对象是否符合函数中的要求 ;


5 . count 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

//查找年龄小于 19 岁的学生个数
var ageLess19 : Int = students.count {
    it.age < 19
}
println(ageLess19)

② 执行结果 :

3


X . find 高阶函数



find 函数原型 : 返回该集合中符合给定谓词要求的第一个元素 ;

/**
 * Returns the first element matching the given [predicate], or `null` if no such element was found.
 */
@kotlin.internal.InlineOnly
public inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
    return firstOrNull(predicate)
}

2 . find 函数的几个要素 :

Iterable<T>.find(predicate: (T) -> Boolean): T?

① 函数调用者 : find 函数是被 Iterable<T> 对象调用的 , 该对象是一个集合 ;

② 函数的参数 : predicate: (T) -> Boolean 是函数参数 ;

③ 函数返回值 : 返回值是 T 类型 , 该集合中如果存在符合某种条件的元素 , 返回第一个该元素 , 使用 ? 修饰说明该值不能为空 ;


3 . find 函数类型参数解析 : predicate: (T) -> Boolean , 这是一个函数类型参数 ; predicate有 谓词 含义;


① predicate: 函数类型变量名 ;

② (T) -> Boolean 是函数参数的类型 : 该函数类型的参数是 T 类型 , T 是集合元素类型 ; 返回值是 Boolean 类型 , 函数的执行内容 : 如果 T 类型参数符合函数中的要求 , 返回 true , 反之返回 false ;


4 . find 高阶函数对函数类型参数的使用 : 传入一个函数类型变量 predicate: (T) -> Boolean , 该函数类型变量通过 predicate(T) 进行调用 , 执行该函数返回 Boolean 值 , 表示该 T 类型对象是否符合函数中的要求 ;


5 . find 高阶函数示例 :


① 代码示例 :

data class Student(var name : String, var age : Int, var height : Int)

var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)

//...

//查找第一个年龄 18 岁的学生
var first18Student = students.find {
    it.age == 18
}
println(first18Student)

② 执行结果 :

Student(name=Jerry, age=18, height=165)


XI . Kotlin 语言集合中的高阶函数 代码示例



1 . 代码示例 :

package list

/**
 * data class 类能快速帮助开发者封装 各种类型的数据 ,
 *      编译后生成的 JavaBean 只生成最基本的几个函数 ,
 *      如 hashCode() , toString() , copy() 等
 *
 * 定义时需要将 要封装的字段写在构造函数中 , 格式如下
 *      var / val 变量名 : 变量类型
 *
 * 参数要求 : 构造函数必有 >= 1 个参数 , 参数格式必须按照上述格式声明
 * 修饰 : data class 不能被 abstract / inner / open / sealed 修饰
 * 继承关系 : data class 可以实现接口 , 在 1.1 版本后 , 可以继承
 */
data class Student(var name : String, var age : Int, var height : Int)

/**
 * 声明 List 集合 , 其中有两个 Student 对象
 */
var students : List<Student> = listOf<Student>(
    Student("Tom", 12, 190),
    Student("Jerry", 18, 165),
    Student("Trump", 18, 178),
    Student("Jack", 29, 165)
)


fun main() {

    //筛选出 students 中 18 岁的学生 , 并打印出来
    filterByAge(18);

    /*
        如果有很多类型的筛选 , 需要些好很多 filterBy 方法 ;
            如按照身高筛选 , 按照名字筛选 , 按照年龄筛选
            每种类型都要写一种方法 , 非常繁琐
            开发时间长了 , 很难维护

        解决上述问题的方案 :
            行为参数化 : 将筛选操作封装在函数中 , 将该函数传递给过滤器
            高阶函数 : 使用函数类型作为 参数 或 返回值 的函数 , 是高阶函数

        下面的示例就是使用高阶函数解决上述问题 :
     */

    /*

        List 高级函数 :


        maxBy minBy 高阶函数 :


        选出年龄最大的学生

        Java 语言逻辑 : 首先要遍历集合获取最大的年龄 , 然后逐个遍历查找年龄最大的的学生

        调用 集合的 maxBy 方法 , 即可获取值最大的元素 , 并且添加到返回的子集合中

        **
         * Returns the first element yielding the largest value of the given function or `null` if there are no elements.
         *
         * @sample samples.collections.Collections.Aggregates.maxBy
         *
        public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? {
            val iterator = iterator()
            if (!iterator.hasNext()) return null
            var maxElem = iterator.next()
            if (!iterator.hasNext()) return maxElem
            var maxValue = selector(maxElem)
            do {
                val e = iterator.next()
                val v = selector(e)
                if (maxValue < v) {
                    maxElem = e
                    maxValue = v
                }
            } while (iterator.hasNext())
            return maxElem
        }


        maxBy 函数需要传入 selector: (T) -> R 参数 , 这是一个函数类型参数 ,
            selector 是变量名 ,
            (T) -> R 是函数类型 :
                T 是迭代器类型 , Iterable<T> , 代表 Student 学生类型
                R 是返回值类型

        maxBy 和 minBy 都是返回 集合中的 最大 或 最小 的第一个元素



        filter 高阶函数 :


        **
         * Returns a list containing only elements matching the given [predicate].
         *
        public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
            return filterTo(ArrayList<T>(), predicate)
        }

        filter 是查找特定条件的元素
            filter 函数接收参数 predicate: (T) -> Boolean
                predicate 是函数类型变量名
                (T) -> Boolean 是函数类型 , 其参数是元素类型对象 , 即 Student 对象 , 返回值是布尔值



        map 高阶函数 :
            作用 : 将某个属性映射成新的集合 , 如将学生的 年龄 放到一个新的 Int 集合中 , 名字放到新的 String 集合中

            map 接收 transform: (T) -> R 参数 :
                transform 是函数类型变量名
                (T) -> R 是函数类型 , T 类型是参数类型 , R 类型是返回值类型 ,

            在 map 函数中 , 创建了一个 R 类型的集合 , 并根据 传入的 T 类型元素生成 R 类型元素 , 将 R 类型元素放到对应集合中

        **
         * Returns a list containing the results of applying the given [transform] function
         * to each element in the original collection.
         *
         * @sample samples.collections.Collections.Transformations.map
         *
        public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
            return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
        }



        any 高阶函数
            传入 predicate: (T) -> Boolean 参数
                参数类型是 (T) -> Boolean 函数类型 , 函数类型中的参数是 T 元素类型 , 返回值是 布尔值

            获取集合中是否有符合某种条件的元素

        **
         * Returns `true` if at least one element matches the given [predicate].
         *
         * @sample samples.collections.Collections.Aggregates.anyWithPredicate
         *
        public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
            if (this is Collection && isEmpty()) return false
            for (element in this) if (predicate(element)) return true
            return false
        }


        count 高阶函数 : 统计符合条件元素的个数

            count 方法传入的函数类型 predicate: (T) -> Boolean
                predicate: (T) -> Boolean 函数类型
                    函数类型实例名称 : predicate
                    参数 : predicate: (T) -> Boolean
                    返回值 : Boolean 布尔值

            count 方法返回值 : Int 类型 , 返回符合 predicate: (T) -> Boolean 函数类型实例执行返回 true 的元素个数

        public inline fun <T> Iterable<T>.count(predicate: (T) -> Boolean): Int {
            if (this is Collection && isEmpty()) return 0
            var count = 0
            for (element in this) if (predicate(element)) checkCountOverflow(++count)
            return count
        }


        find 高阶函数 : 查找第一个符合条件的元素

        find 函数参数 : predicate: (T) -> Boolean 函数类型变量
        find 函数返回值 : T 类型的元素对象 , 返回符合 传入的函数变量执行返回 true 的元素集合的第一个元素

        predicate: (T) -> Boolean 函数类型 :

        public inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
            return firstOrNull(predicate)
        }


        groupBy 高阶函数 : 将元素分组


     */

    // 获取年龄最大的学生
    var maxAgeStudent = students.maxBy { it.age }
    println(maxAgeStudent)

    // 获取身高最低的学生
    var minHeightStudent = students.minBy { it.height }
    println(minHeightStudent)


    // 筛选出年龄大于 15 , 并且身高小于 180 的学生 , 其返回值是一个集合
    //  后面可以有多个 and 连接多个判断语句
    var ageH15HeightLow180 = students.filter {
        (it.age > 15 ) and (it.height < 180)
    }
    println(ageH15HeightLow180)


    //将 Student 对象中的 姓名 和 年龄抽取出来 , 拼接成 "姓名 : 年龄" 字符串, 放到一个新的 字符串集合中
    var studentNameAgess = students.map {
        "${it.name} : ${it.age}"
    }
    println(studentNameAgess)


    //集合中是否有 18 岁的学生
    var is18AgeExist : Boolean = students.any{
        it.age == 18
    }
    println(is18AgeExist)


    //查找年龄小于 19 岁的学生个数
    var ageLess19 : Int = students.count {
        it.age < 19
    }
    println(ageLess19)

    //查找第一个年龄 18 岁的学生
    var first18Student = students.find {
        it.age == 18
    }
    println(first18Student)


    //按照年龄分组 , 结果是 map 集合
    var groupAgeResult = students.groupBy { it.age }
    println(groupAgeResult)

    //按照身高分组 , 结果是 map 集合 , 获取 165 身高的学生 , 并且遍历打印出来
    students.groupBy { it.height }.get(165)?.forEach { println(it) }

}

/**
 * 筛选出 students 中 18 岁的学生 , 并打印出来
 *
 * 这是按照 Java 代码的逻辑写的
 */
fun filterByAge(age : Int){

    // 1 . 先创建一个集合
    var filterStudents : ArrayList<Student> = ArrayList<Student>()

    // 2 . 遍历 students 集合 , 并将 18 岁的筛选出来
    for (student in students){
        if(student.age == age){
            filterStudents.add(student);
        }
    }

    // 3 . 打印筛选出的学生
    for(student in filterStudents){
        println("${student.name} , ${student.age} , ${student.height}")
    }

}

2 . 执行结果 :

Jerry , 18 , 165
Trump , 18 , 178
Student(name=Jack, age=29, height=165)
Student(name=Jerry, age=18, height=165)
[Student(name=Jerry, age=18, height=165), Student(name=Trump, age=18, height=178), Student(name=Jack, age=29, height=165)]
[Tom : 12, Jerry : 18, Trump : 18, Jack : 29]
true
3
Student(name=Jerry, age=18, height=165)
{12=[Student(name=Tom, age=12, height=190)], 18=[Student(name=Jerry, age=18, height=165), Student(name=Trump, age=18, height=178)], 29=[Student(name=Jack, age=29, height=165)]}
Student(name=Jerry, age=18, height=165)
Student(name=Jack, age=29, height=165)