当前位置: 首页 > 编程笔记 >

详解Kotlin:forEach也能break和continue

林修雅
2023-03-14
本文向大家介绍详解Kotlin:forEach也能break和continue,包括了详解Kotlin:forEach也能break和continue的使用技巧和注意事项,需要的朋友参考一下

详解Kotlin:forEach也能break和continue

这样的问题。也就是说,他们想用forEach而不是for循环,因为这很fp,很洋气(我也喜欢),

但是他们又想使用break和continue,也就是普通的流程控制语句中的控制语句。

这很不fp,因为原本有filter是用于完成这个工作的,还有flapMap。BennyHuo在他发的文章里面也说的是这种方法。

filter很fp,但是会导致两次遍历,这样的话给人一股效率很低的赶脚。而Java8的Stream API就只会遍历一次,
而且很fp。但是它会有lambda对象的产生而且实现超复杂(我没看过,不清楚),而Kotlin的集合框架可是能inline掉lambda的,

少产生了多少对象啊,怎么能和辣鸡Java同流合污呢?

有人提到使用label return,比如:

fun main(ags: Array<String>) {
 (0..100).forEach {
  if (50 <= it) return@forEach
  println(it)
 }
}

但是他做了实验之后发现这玩意只能相当于continue,也就是说你只能跳出当前循环,然后还是会继续下一轮。

讲道理这个你仔细想想就可以发现。为了搞清楚其中的道理,我们自己实现一个forEach。

fun Pair<Int, Int>.forEach(block: (Int) -> Unit) {
 for (i in first..second) block.invoke(i)
}

然后调用一下:

Pair(1, 100).forEach(::println)

没毛病老铁。

然后你会发现,你在函数体内对block产生了(second - first)次调用,不论你怎么return,都只会跳出这个block,
它并不影响你之后继续调用这个block,也就是说这个for循环不受block行为的影响。

看起来无解了,那怎么办呢?

那么就让我来拯救你们吧。

fun main(ags: Array<String>) {
 run outside@ {
  (0..20).forEach inside@ {
   if (10 <= it) return@outside
   println(it)
  }
 }
}

编译之后运行结果:

0
1
2
3
4
5
6
7
8
9
Process finished with exit code 0

呐,跳出去了。

把label的名字起的清真一点,就是这样:

run breaking@ {
 (0..20).forEach continuing@ {
  if (10 <= it) return@breaking
  println(it)
 }
}

上面这是break,运行结果就上面那样。

下面这是continue,运行结果就是continue的效果。为了让效果表现的明显,我把println复制了一下,
分别在if前后,这样可以很清楚地看到效果。

run breaking@ {
 (0..20).forEach continuing@ {
  print(it)
  if (10 <= it) return@continuing
  println(it)
 }
}

运行一下:

00
11
22
33
44
55
66
77
88
99
1011121314151617181920
Process finished with exit code 0

而且只进行了一次迭代,非常清真,效率看起来也比较高。

如何证明只有一次迭代?我使用jd-gui逆向了刚才的代码,结果:

public final class _5Kt
{
 public static final void main(@NotNull String[] args)
 {
  Intrinsics.checkParameterIsNotNull(args, "args");
  int $i$a$1$run;
  Iterable $receiver$iv = (Iterable)new IntRange(0, 20);
  int $i$f$forEach;
  for (Iterator localIterator = $receiver$iv.iterator(); localIterator.hasNext();)
  {
   int element$iv = ((IntIterator)localIterator).nextInt();int it = element$iv;
   int $i$a$1$forEach;
   System.out.print(it);
   if (10 <= it) {
    break;
   }
   System.out.println(it);
  }
 }
}

确实只有一次,而且jd-gui直接把我的行为反编译为break了。服不服?

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

 类似资料:
  • 主要内容:使用 break 语句直接强行退出循环(break 不带标签),使用 break 语句实现 goto 的功能(break 带标签),在 switch 语句中终止一个语句序列某些时候需要在某种条件出现时强行终止循环,而不是等到循环条件为 false 时才退出循环。此时,可以使用 break 来完成这个功能。 break 用于完全结束一个循环,跳出循环体。不管是哪种循环,一旦在循环体中遇到 break,系统将完全结束该循环,开始执行循环之后的代码。 在 Java 中,break 语句有 3

  • break 语句 break 用来终止 while、repeat 和 for 三种循环的执行,并跳出当前循环体, 继续执行当前循环之后的语句。下面举一个 while 循环中的 break 的例子来说明: -- 计算最小的x,使从1到x的所有数相加和大于100 sum = 0 i = 1 while true do sum = sum + i if sum > 100 then

  • 本文向大家介绍python中break、continue 、exit() 、pass终止循环的区别详解,包括了python中break、continue 、exit() 、pass终止循环的区别详解的使用技巧和注意事项,需要的朋友参考一下 python中break、continue 、exit() 、pass区分 1、break:跳出循环,不再执行 Python break语句,就像在C语言中,打

  • break和continue语句改变控制流程。break语句在while、for、do/while或switch结构中执行时,使得程序立即退出这些结构,从而执行该结构后面的第一条语句。break语句常用于提前从循环退出或跳过switch结构的其余部分(如图2.22)。图2.26演示了for重复结构中的break语句,if结构发现x变为5时执行break,从而终止for语句,程序继续执行for结构后

  • 4. break和continue语句 在第 4 节 “switch语句”中我们见到了break语句的一种用法,用来跳出switch语句块,这个语句也可以用来跳出循环体。continue语句也会终止当前循环,和break语句不同的是,continue语句终止当前循环后又回到循环体的开头准备执行下一次循环。对于while循环和do/while循环,执行continue语句之后测试控制表达式,如果值为

  • 问题内容: 可以将这段代码转换为列表理解吗? 我知道如何转换它的一部分: 但是我不知道如何添加中断,并且文档没有太大帮助。 任何帮助,将不胜感激。 问题答案: 分解一下: 将产生一个清单。您想要的是列表中的第一项。一种方法是使用下一个功能: Next返回迭代器的下一项。在像列表这样的可迭代的情况下,它最终采用了第一项。 但是没有理由真正构建列表,因此我们可以改用生成器表达式: 另外,请注意,如果生