详解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了。服不服?

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

(0)

相关推荐

  • java中break和continue源码解析

    在自己学习java语言的过程中,很容易把break和continue的用法混淆.为了便于以后快速查阅及温习,在此特留学习笔记一份. 简述 在任何迭代语句的主体部分,都可以用break和continue控制循环的流程.其中,break用于强行退出循环,不执行循环中剩余的语句.而continue则停止执行当前迭代,然后退回循环起始处,开始下一次迭代. 源码 下面这个程序向大家展示了break和continue在for和while循环中的例子: package com.mufeng.thefourth

  • C++编程中break语句和continue语句的学习教程

    break 语句 break 语句可终止执行最近的封闭循环或其所在条件语句. 控制权将传递给该语句结束之后的语句(如果有的话). break; 备注 break 语句与 switch 条件语句以及 do.for 和 while 循环语句配合使用. 在 switch 语句中,break 语句将导致程序执行 switch 语句之外的下一语句. 如果没有 break 语句,则将执行从匹配的 case 标签到 switch 语句末尾之间的每个语句,包括 default 子句. 在循环中,break 语句

  • C/C++ break和continue区别及使用方法

    C/C++ break和continue区别及使用方法 break可以离开当前switch.for.while.do while的程序块,并前进至程序块后下一条语句,在switch中主要用来中断下一个case的比较.在for.while与do while中,主要用于中断目前的循环执行. continue的作用与break类似,主要用于循环,所不同的是break会结束程序块的执行,而continue只会结束其之后程序块的语句,并跳回循环程序块的开头继续下一个循环,而不是离开循环. 1. #incl

  • javaScript如何跳出多重循环break、continue

    先来说说break和continue之间的区别 摘自JavaScript高级程序设计 for(var i=0;i<10;i++){ if(i>5){ break; } } console.log(i); ---6 •当i=5和10的时候,会执行到break,并退出循环 for(var i=1;i<10;i++){ if(i>5){ continue; } num++; } console.log(num); ---4 var num=0; for(var i=1;i<10;i

  • 关于break和continue以及label的区别和作用(详解)

    break和continue的区别和作用: break用于完全结束一个循环[一般只退出一重循环],跳出循环体执行循环后面的语句 continue是跳过当次循环中剩下的语句,执行下一次循环. 标号label 标号提供了一种简单的break语句所不能实现的控制循环的方法,当在循环语句中碰到break时, 不管其它控制变量,都会终止.但是,当你嵌套在几层循环中想退出循环时又怎么办呢?break只退出一重循环, 但你可以用标号label标出你想退出哪一个语句.规定标号label必需放在循环之前(意味着循

  • 详解Kotlin:forEach也能break和continue

    详解Kotlin:forEach也能break和continue 这样的问题.也就是说,他们想用forEach而不是for循环,因为这很fp,很洋气(我也喜欢), 但是他们又想使用break和continue,也就是普通的流程控制语句中的控制语句. 这很不fp,因为原本有filter是用于完成这个工作的,还有flapMap.BennyHuo在他发的文章里面也说的是这种方法. filter很fp,但是会导致两次遍历,这样的话给人一股效率很低的赶脚.而Java8的Stream API就只会遍历一次,

  • 详解Kotlin 高阶函数 与 Lambda 表达式

    详解Kotlin 高阶函数 与 Lambda 表达式 高阶函数(higher-order function)是一种特殊的函数, 它接受函数作为参数, 或者返回一个函数. 这种函数的一个很好的例子就是 lock() 函数, 它的参数是一个锁对象(lock object), 以及另一个函数, 它首先获取锁, 运行对象函数, 然后再释放锁: fun <T> lock(lock: Lock, body: () -> T): T { lock.lock() try { return body()

  • 详解Kotlin Android开发中的环境配置

    详解Kotlin Android开发中的环境配置 在Android Studio上面进行安装插件 在Settings ->Plugins ->Browse repositores.. ->kotlin 安装完成后重启Android Studio就生效了 如图所示: 在Android Studio中做Kotlin相关配置 (1)在根目录 的build.gradle中进行配置使用,代码如下: buildscript { ext.kotlin_version = '1.1.2-4' repos

  • 详解Kotlin中的面向对象(二)

    详解Kotlin中的面向对象(二) 在Kotlin中的面向对象(一)中,介绍了Kotlin类的相关操作,本文将在上文的基础上,继续介绍属性.接口等同样重要的面向对象的功能. 属性 class AttrDemo{ private var attr1 : String = ""; protected var attr2 : String = ""; public var attr3 : String = ""; var varattr : Strin

  • 详解Kotlin中的变量和方法

    详解Kotlin中的变量和方法 变量 Kotlin 有两个关键字定义变量:var 和 val, 变量的类型在后面. var 定义的是可变变量,变量可以被重复赋值.val 定义的是只读变量,相当于java的final变量. 变量的类型,如果可以根据赋值推测,可以省略. var name: String = "jason" name = "jame" val max = 10 常量 Java 定义常量用关键字 static final, Kotlin 没有static,

  • 详解Kotlin的空指针处理

    详解Kotlin的空指针处理 Kotlin的空指针处理相比于java有着极大的提高,可以说是不用担心出现NullPointerException的错误,kotlin对于对象为null的情况有严格的界定,编码的阶段就需要用代码表明引用是否可以为null,为null的情况需要强制性的判断处理. 咋看一下这些在java里面其实也有,问题是一般开发中不写也是可以的(大部分开发不会花很多时间考虑这些),等出了空指针错误再一个个打补丁.这样往往会遗漏很多空指针,后期的解决仅仅是做一个if判断,没有从根源解决

  • 详解 Kotlin Reference Basic Types, String, Array and Imports

    详解 Kotlin Reference  Basic Types, String, Array and Imports 基本数据类型 Kotlin中支持的基本数据类型及它所占Bit宽度: Type Bit width Double 64 Float 32 Long 64 Int 32 Short 16 Byte 8 Char 在kotlin中 并不是一个数值类型 kotlin不支持8进制, 支持 2.10.16进制 下面的代码,示例了: 关于2.10.16进制: 使用下划线在数值常量赋值数据中:

  • 详解 Kotlin Reference  Basic Types, String, Array and Imports

    详解 Kotlin Reference  Basic Types, String, Array and Imports 基本数据类型 Kotlin中支持的基本数据类型及它所占Bit宽度: Type Bit width Double 64 Float 32 Long 64 Int 32 Short 16 Byte 8 Char 在kotlin中 并不是一个数值类型 kotlin不支持8进制, 支持 2.10.16进制 下面的代码,示例了: 关于2.10.16进制: 使用下划线在数值常量赋值数据中:

  • 详解Kotlin中如何实现类似Java或C#中的静态方法

    大家可以在网络上搜到不少这样的文章,官方推荐是包级函数,也有人说用伴生对象(companion class).这些都是不错的选择,但并不完善,我们在不同的情况下有更好的选择.我总结了几种方法,分别是:包级函数.伴生对象.扩展函数和对象声明.这需要大家根据不同的情况进行选择. 一.包级函数 Kotlin和Java及C#不同的是,可以在包里面直接声明函数.做法和类中是一样的,这里就不多说了,的确是一个非常好的选择.适用于函数不需要不包内部的类进行数据共享的方法. 二.伴生对象 从语义上来讲,伴生函数

  • 详解Kotlin和anko融合进行Android开发

    kotlin是一门基于jvm的编程语言,最近进行了关于kotlin和 anko的研究.并且结合现在的APP设计模式,设想了初步的开发方式.并且准备应用在新的项目中. Kotlin和anko Kotlin是大名鼎鼎的JB公司开发的jvm语言,官网地址为:http://kotlinlang.org/ 官网的介绍为: Statically typed programming language for the JVM, Android and the browser Kotlin的设计思想非常的轻量,尽

随机推荐