如何找到 IntelliJ Kotlin lint 检查背后的原因
How to find the reasoning behind IntelliJ Kotlin lint check
我在使用 IntelliJ 作为我的 IDE 编写 Kotlin 时收到一条 lint 消息:The argument can be converted to 'Set' to improve performance
我的代码是这样的:
val variable3 = variable1 - variable2
变量的类型是 List<Int>
linter 推荐我改成 val variable3 = variable1 - variable2.toSet()
我想知道为什么它建议进行此更改以及文档在哪里,以便下次我可以查找消息并了解 lint 检查背后的原因。
您可以将鼠标悬停在上面并打开文档,如下所示:
一般快速修复选项可以在on/off下找到并打开
设置 -> 检查 -> kotlin(示例)
这是关于性能和效率的——特别是关于性能如何随着数据变大而扩展。
-
运算符调用标准库的 Iterable<T>.minus(elements: Iterable<T>)
扩展函数。如果您查看它的代码(您可以在 IntelliJ 中执行此操作),您会发现它的工作原理是获取第一个可迭代对象(在本例中为 variable1
)并过滤它以仅保留值 在第二个 (variable2
) 中不是 。
它如何检查一个元素是否在第二个元素中?通过调用其 contains()
方法。但是 that 的工作方式将取决于可迭代对象的类型。例如,大多数 Set
可以通过哈希码查找,无论集合有多大,这都需要很短的时间。
然而,大多数 List
和其他可迭代对象无法做到这一点:它们需要逐个元素地搜索整个列表。这需要多长时间显然取决于列表的大小——对于短列表来说会非常快,但搜索具有数千或数百万个元素的列表可能需要一些时间。
在这种情况下特别重要的是它必须重复搜索:对第一个元素的每个元素搜索一次。所以时间真的可以加起来。
假设第一个 iterable 有元素,第二个有 .减法必须进行检查;如果第二个是一个集合,那么每次检查大约需要相同的时间,所以整体时间与 成正比。但如果不是,那么每次检查所花费的时间与(例如,如果您将每个列表扩大 10 倍,则需要 100 倍的时间。)
因此,如果您不希望您的程序在开始处理更多数据时陷入停顿,那么首先将第二个列表转换为集合是非常值得的。对于少量数据,它会增加一些额外的工作,但这可能不会引起注意;对于大量数据,这可能是一个巨大的胜利。
这就是 IntelliJ 检查建议它的原因。
(对于那些了解算法复杂性的人,请原谅我在这里所做的简化:)
有趣的是,当我自己尝试时(在 IntelliJ 2021.2.3 和 Kotlin v1.5.73 中),它并没有提出那个建议。查看标准库的实现,我发现在某些情况下 minus()
方法会为您进行转换!但是,我认为它没有涵盖其他一些常见情况,因此如果您认为列表可能会变大,仍然值得自己进行转换。
我在使用 IntelliJ 作为我的 IDE 编写 Kotlin 时收到一条 lint 消息:The argument can be converted to 'Set' to improve performance
我的代码是这样的:
val variable3 = variable1 - variable2
变量的类型是 List<Int>
linter 推荐我改成 val variable3 = variable1 - variable2.toSet()
我想知道为什么它建议进行此更改以及文档在哪里,以便下次我可以查找消息并了解 lint 检查背后的原因。
您可以将鼠标悬停在上面并打开文档,如下所示:
一般快速修复选项可以在on/off下找到并打开 设置 -> 检查 -> kotlin(示例)
这是关于性能和效率的——特别是关于性能如何随着数据变大而扩展。
-
运算符调用标准库的 Iterable<T>.minus(elements: Iterable<T>)
扩展函数。如果您查看它的代码(您可以在 IntelliJ 中执行此操作),您会发现它的工作原理是获取第一个可迭代对象(在本例中为 variable1
)并过滤它以仅保留值 在第二个 (variable2
) 中不是 。
它如何检查一个元素是否在第二个元素中?通过调用其 contains()
方法。但是 that 的工作方式将取决于可迭代对象的类型。例如,大多数 Set
可以通过哈希码查找,无论集合有多大,这都需要很短的时间。
然而,大多数 List
和其他可迭代对象无法做到这一点:它们需要逐个元素地搜索整个列表。这需要多长时间显然取决于列表的大小——对于短列表来说会非常快,但搜索具有数千或数百万个元素的列表可能需要一些时间。
在这种情况下特别重要的是它必须重复搜索:对第一个元素的每个元素搜索一次。所以时间真的可以加起来。
假设第一个 iterable 有元素,第二个有 .减法必须进行检查;如果第二个是一个集合,那么每次检查大约需要相同的时间,所以整体时间与 成正比。但如果不是,那么每次检查所花费的时间与(例如,如果您将每个列表扩大 10 倍,则需要 100 倍的时间。)
因此,如果您不希望您的程序在开始处理更多数据时陷入停顿,那么首先将第二个列表转换为集合是非常值得的。对于少量数据,它会增加一些额外的工作,但这可能不会引起注意;对于大量数据,这可能是一个巨大的胜利。
这就是 IntelliJ 检查建议它的原因。
(对于那些了解算法复杂性的人,请原谅我在这里所做的简化:)
有趣的是,当我自己尝试时(在 IntelliJ 2021.2.3 和 Kotlin v1.5.73 中),它并没有提出那个建议。查看标准库的实现,我发现在某些情况下 minus()
方法会为您进行转换!但是,我认为它没有涵盖其他一些常见情况,因此如果您认为列表可能会变大,仍然值得自己进行转换。