详解Kotlin:forEach也能break和continue

 更新时间:2017年06月13日 08:46:47   投稿:lqh  
这篇文章主要介绍了详解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

呐,跳出去了。

就是这样:

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

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

相关文章

  • SpringBoot中使用com.alibaba.druid.filter.config.ConfigTools对数据库密码加密的方法

    SpringBoot中使用com.alibaba.druid.filter.config.ConfigTools对数据库

    这篇文章主要介绍了SpringBoot中使用com.alibaba.druid.filter.config.ConfigTools对数据库密码加密的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Java线程池流程编排运用实战源码

    Java线程池流程编排运用实战源码

    这篇文章主要介绍了Java线程池流程编排运用实战源码,就在流程引擎的基础上运用 ThreadPoolExecutor,使用线程池实现 SpringBean 的异步执行
    2022-03-03
  • 已有的springcloud+mybatis项目升级为mybatis-plus的方法

    已有的springcloud+mybatis项目升级为mybatis-plus的方法

    这篇文章主要介绍了已有的springcloud+mybatis项目升级为mybatis-plus,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • idea中项目文件目录消失如何解决

    idea中项目文件目录消失如何解决

    这篇文章主要介绍了idea中项目文件目录消失的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 解析spring-security权限控制和校验的问题

    解析spring-security权限控制和校验的问题

    这篇文章主要介绍了解析spring-security权限控制和校验的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • java实现微信扫码登录第三方网站功能(原理和代码)

    java实现微信扫码登录第三方网站功能(原理和代码)

    为避免繁琐的注册登陆,很多平台和网站都会实现三方登陆的功能,增强用户的粘性。这篇文章主要介绍了java实现微信扫码登录第三方网站功能(原理和代码),避免做微信登录开发的朋友们少走弯路
    2022-12-12
  • Maven 继承父工程时的relativePath标签详细解析

    Maven 继承父工程时的relativePath标签详细解析

    这篇文章主要介绍了Maven 继承父工程时的relativePath标签解析,通过本文学习你需要注意子模块想要用父模块pom中的版本,请注意配置relativePath属性,需要的朋友可以参考下
    2022-12-12
  • springboot-mybatis/JPA流式查询的多种实现方式

    springboot-mybatis/JPA流式查询的多种实现方式

    这篇文章主要介绍了springboot-mybatis/JPA流式查询,本文给大家分享三种方式,每种方式结合示例代码给大家讲解的非常详细,需要的朋友可以参考下
    2022-12-12
  • java中的内部类内部接口用法说明

    java中的内部类内部接口用法说明

    这篇文章主要介绍了java中的内部类内部接口用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • SpringBoot项目离线环境手动构建的过程

    SpringBoot项目离线环境手动构建的过程

    文章介绍了如何在IntelliJ IDEA中手动创建一个Spring Boot项目,并详细讲解了pom.xml文件的配置和基本项目结构的设置,感兴趣的朋友跟随小编一起看看吧
    2025-01-01

最新评论