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设置开机启动程序

    1.新建文件,填写路径 @echo off cd F:\程序路径\ //后面填写3D所在的路径 F: //程序的个盘符 run.bat 把这个文件填写完成后,改个名字,后缀改为bat,并把这个文件放在 ...

  2. python不确定性计算之粗糙集属性约简

    粗糙集属性约简 本实验同时采用区别矩阵和依赖度约简. 在依赖度约简中,设置依赖度计算函数和相对约简函数,对读取的数据进行处理,最后根据依赖度约简. 在读取数据后判断有无矛盾,若有则进行决策表分解,然后 ...

  3. 二、docker安装

    一.docker安装 Docker 是管理容器的工具, Docker 不等于 容器. 1.1.docker yum源设置 #step 1 download docker-ce.repo file [r ...

  4. mysql 子查询 联结 组合查询

    子查询 SELECT cust_id FROM orders WHERE order_num IN (SELECT order_num FROM orderitems WHERE prod_id='T ...

  5. C语言白盒测试讲义

    好久没有做过C语言的白盒测试了,估计以后也没这个机会.把自己之前参加过的培训素材做个分享. 素材下载链接:https://pan.baidu.com/s/1LPD9Az04zEj8RuCICaKYxQ ...

  6. 要写文档了,emmm,先写个文档工具吧——DocMarkdown

    前言 之前想用Markdown来写框架文档,找来找去发现还是Jekyll的多,但又感觉不是很合我的需求 于是打算自己简单弄一个展示Markdown文档的网站工具,要支持多版本.多语言.导航.页内导航等 ...

  7. KeeWiDB的高性能修炼之路:架构篇

    数据也有冷热之分,你知道吗? 根据访问的频率的高低可将数据分为热数据和冷数据,访问频率高的则为热数据,低为冷数据.如果热.冷数据不区分,一并存储,显然不科学.将冷数据也存储在昂贵的内存中,那么你想,成 ...

  8. ES的java端API操作

    首先简单介绍下写这篇博文的背景,最近负责的一个聚合型的新项目要大量使用ES的检索功能,之前对es的了解还只是纯理论最多加个基于postman的索引创建操作,所以这次我得了解在java端如何编码实现:网 ...

  9. redis的缓存穿透、击穿、雪崩以及实用解决方案

    今天来聊聊redis的缓存穿透.击穿.雪崩以及解决方案,其中解决方案包括类似于布隆过滤器这种网上一搜一大片但是实际生产部署有一定复杂度的,也有基于spring注解通过一行代码就能解决的,其中各有优劣, ...

  10. Debian Linux 的安装

    Debian Linux 的安装 作者:Grey 原文地址: 博客园:Debian Linux 的安装 CSDN:Debian Linux 的安装 说明 本安装说明是基于 Windows 10 下 V ...