for

起因

记得大学上C语言的课,第一次遇到的问题就是循环结构里面的 for

选择结构的 if 非常易懂,和日常生活的判断没有区别。

循环结构的 while 同样比较好理解。

本质上是一个判断

  • 如果为真,继续循环。
  • 如果不假,则退出循环。

for 会稍微复杂一些。

for (init-expr; test-expr; update-expr)
body-statement
  1. 初始化表达式只执行一次
  2. 判断表达式执行
    • 判断为真执行循环体
    • 判断为假退出循环体
  3. 执行更新表达式

在实际的语义等同于(唯一区别是init-expr一个是内部变量,一个是外部变量)

    init-expr
while (test-expr) {
body-statement
update-expr
}

那么我们为什么要设计一个不那么好理解的循环结构呢?

因为这时候才入了编程的门————抽象,以及约定。

如果我们再往底层挖,会发现在汇编语言中是不存在whilefor 关键字的。

最开始的程序总是从左到右,从上到下一条路走到黑的。

后面编程人员意识到编写重复的代码过于麻烦才创造了 loop

所以最开始需要人工写一个for或者while循环。

while 好理解在于和自然语言(英语)完全符合。

    当 条件满足 时, {
执行 流程;
}

for 循环的好处在于规范了 while 的使用。

  1. 初始化语句(init-expr)一般只用于循环,所以放在内部,便于回收变量。
  2. 循环条件(test-expr)一般配合更新语句一起使用(update-expr),实现循环有限次数。
  3. 三者的拆分使编写大段的循环或者嵌套循环时,更易读。
// 传统while循环
int i = 0;
while (i < 10) {
handleX();
i++;
int j = 0;
while (j < 5) {
handleY();
j++;
}
}
// for循环
for (int i = 0; i < 10; i++) {
handleX();
for (int j = 0; j < 5; j++) {
handleY();
}
}

所以 for 循环的出现也意味着编程人员开始在意的不仅仅是功能,而且看重可读性。

然而这并不会被满足。

之后还出现了

  1. 增强 for,部分语言的for-each,for...in
  2. lamdba 表达式中的 forEach() 方法。

注意:以下按 Java 实现的 foreach 举例。(其他编程语言不太熟悉)

增强 for

foreach 的规则

  1. 所有使用 foreach 的集合都必须实现 Iterable 接口
  2. 通过 iterator() 获取 iterator 对象
  3. 通过 iterator.hasNext() 判断是否存在元素。
  4. 通过 iterator.next() 获取下一个元素。
  5. 通过 iterator.remove() 移除返回的元素。(可选)

增强 for 的语法

    List<String> list = Arrays.asList("1", "2", "3", "4", "5");
// for 版本
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// foreach 版本
for (String e : list) {
System.out.println(e);
}
// 去"糖"后的while版本
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}

可以看出,foreach 对于 for、while 来说,好处是更加简单,符合直觉。

  1. 无需判断集合个数和中间变量减少代码出错可能性,统一通过 hasNext() 处理。
  2. 不用分析每个集合类如何获取元素,统一通过 next() 处理。
  3. 通过语法糖隐藏了 hasNext(), next() 逻辑,代码更易读。

forEach()

Java 7/8 受到了函数式语言的影响,实现了更简练的写法。

    // Iterable<T> 内实现的forEach
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
} List<String> list = Arrays.asList("1", "2", "3", "4", "5");
// forEach()
list.forEach(i -> System.out.print(i));
// 方法引用
list.forEach(System.out::print);

可以看出,forEach()的好处显而易见。

  1. 代码量比 foreach 更少,只关注遍历元素,甚至连元素类型都可以省略。
  2. 使用了方法引用后更进一步,我们关注的是这个集合执行了哪些操作,遍历每一次的含义在forEach()的方法已经体现了,甚至不需要写遍历的元素。

总结

可以看出,编程人员一直追寻的是更简单,更易读的代码。

  • 他们不满足于汇编语言一遍遍的写同一行代码,创造了 while
  • 不满足于 复杂或多层 while 的不可读, 创造了 for
  • 不满足于 for 循环每一次定义的中间变量,创造了 foreach
  • 不满足于 foreach 需要循环每一次的元素,利用了lamdba 的 Consumer, 去掉了元素。

琐碎的想法(五)for 的前世今生的更多相关文章

  1. Python-装饰器(语法糖)上下五千年和前世今生

    装饰器上下五千年和前世今生,这里我们始终要问,装饰器为何产生?装饰器产生解决了什么问题?什么样的需求推动了装饰器的产生?思考问题的时候,始终要问,为什么要这样,而不是那样或者其他样.这里我不先说,也不 ...

  2. 琐碎的想法(三)对Java的批评的看法

    编写本文的目的 在大环境下,Java是一个饱受争议的语言,一方面在工程上它的流行程度非常高:另一方面,越是资深的软件工程师就越容易对这个语言感到不满. 在这种情况下,博主希望每一个Java程序员能够耐 ...

  3. 《principles of model checking》中的离散时间马尔科夫链

    <principles of model checking>中的离散时间马尔科夫链 说明:此文为我自学<principles of model checking>第十章内容的笔 ...

  4. Angular2+ 使用 Protractor 与 Modify Header Value (HTTP Headers) 插件 完成 Windows Authorization 验证

    入职新公司第二周,接到了一个E2E测试的任务,两天的时间把所有的测试条件都写完了,结果剩下三天都卡在了Windows Authorization验证这里. 先说一下公司项目Authorize的逻辑 第 ...

  5. 一个想法(续五):IT联盟创业计划:现阶段进度公示、疑问解答及进行中的计划

    前言: 首先今天是元宵节,先祝大伙元宵节快,单纯的快乐! 然后看看开展中的计划: IT联盟创业计划众筹发起:一个想法(续三):一份IT技术联盟创业计划书,开启众筹创业征程 IT联盟创业计划众筹进度:一 ...

  6. Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介

    Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...

  7. JVM(五)垃圾回收器的前世今生

    全文共 2195 个字,读完大约需要 8 分钟. 如果垃圾回收的算法属于内存回收的方法论的话,那本文讨论的垃圾回收器就属于内存回收的具体实现. 因为不同的厂商(IBM.Oracle),实现的垃圾回收器 ...

  8. JavaScript的前世今生

    和CSS一样,JavaScript在各浏览器下并非完全一致,它所带来的兼容性问题时常困扰着我们,以至于现在“能否处理流行浏览器的兼容性问题”成为了检验一个程序员是否合格的标准之一.了解JavaScri ...

  9. JavaScript 异步编程的前世今生(上)

    前言 提到 JavaScript 异步编程,很多小伙伴都很迷茫,本人花费大约一周的业余时间来对 JS 异步做一个完整的总结,和各位同学共勉共进步! 目录 part1 基础部分 什么是异步 part2 ...

  10. MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信

    MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...

随机推荐

  1. Windows活动目录_初识

    计算机组织形式 工作组(用户本地登录时构造SID进行权限分配): 域(统一身份验证与管理) 域注意事项 实体:域控.域用户.加入域的机子. 依赖的服务:netlogon服务 强制刷新组策略gpupda ...

  2. 42.JSON Web Token认证

    JSON Web Token认证介绍 简称JWT认证,一般用于用户认证 JWT是一种相当新的标准,可用于基于token的身份验证 与内置的TokenAuthentication方案不同,JWT不需要使 ...

  3. Python 嵌入式打包 (图文)

    Python嵌入式打包过程 目录 Python嵌入式打包过程 下载嵌入式包 解压和配置 安装pip和其他依赖 启动项目 python嵌入式打包:将python环境与项目代码打包到同一个文件夹中,在其他 ...

  4. docker常用配置以及命令

    1. Docker基本概念 1.1 什么是 docker hub DockHub是一个仓库 https://hub.docker.com/ 仓库是集中存放镜像文件的场所 仓库分为公开仓库(Public ...

  5. LoadRunner11使用代理录制脚本

    一.背景 电脑安装了LoadRunner11,在进行脚本录制时发现录制的脚本为空,即录制时事件为0,也没有自动调出对应的浏览器:如下图: 问了度娘,发现LR11要成功录制脚本,对各浏览器的版本有要求! ...

  6. Electron是什么以及可以做什么

    新用户购买<Electron + Vue 3 桌面应用开发>,加小册专属微信群,参与群抽奖,送<深入浅出Electron>.<Electron实战>作者签名版. 1 ...

  7. VO层

    springboot中vo的作用: VO:View Object,视图层,其作用是将指定页面的展示数据封装起来,通常用于业务层之间的数据传递. 一般将vo层放置在model层下 类似于将前端页面传输的 ...

  8. 【lwip】11-UDP协议&源码分析

    目录 前言 11.1 传输层说明 11.2 UDP协议简介 11.3 UDP特点 11.4 UDP端口号 11.5 UDP报文 11.6 UDP伪首部和校验和 11.7 wireshark报文分析 1 ...

  9. C++ 中指针常量、指向常量的指针、引用类型的常量

    命题1. 在C++ 中 const T a 与 T const a 是一样的, 表示a是一个T类型的常量. 测试: 一. 形参定义为引用类型的常量 在函数传参时,形参若定义为 const T& ...

  10. c#使用Bitmap绘图的时候,内存增大问题

    最近碰到一个问题,就是使用Biamap绘图的时候,为了防止闪烁,使用了双缓存绘制的方式,但是会碰到内存急剧增加的情况,而且在XP的工控机和Win10的机器上运行结果不一样,在Win10 上运行的时候, ...