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. MySQL开发

    常用数据类型 整数:tinyint.int.bigint小数:decimal.字符串:char.varchar.text 增 insert into 表名(列名,列名)values(值,值): 删 d ...

  2. 齐博x1云市场注意事项

    安装云市场应用注意事项 大到频道,小到插件甚至钩子及风格都可以在线安装,在线升级. 但是有一个大家务必注意的地方,就是重装系统后,再安装有可能导致重复收费. 这个问题是可以解决的.当然如果不是重装系统 ...

  3. 微粒群算法PSO 01背包问题 python

    import random import math import matplotlib.pyplot as plt import numpy as np import time def init(b_ ...

  4. 从源码入手探究一个因useImperativeHandle引起的Bug

    今天本来正在工位上写着一段很普通的业务代码,将其简化后大致如下: function App(props: any) { // 父组件 const subRef = useRef<any>( ...

  5. Netty学习记录-入门篇

    你如果,缓缓把手举起来,举到顶,再突然张开五指,那恭喜你,你刚刚给自己放了个烟花. 模块介绍 netty-bio: 阻塞型网络通信demo. netty-nio: 引入channel(通道).buff ...

  6. $_SERVER["REQUEST_URI"],在 PHP 众多预定义服务器变量中,$_SERVER["REQUEST_URI"] 算是经常用到的,但是这个变量只有 apache 才支持

    例如访问:http://localhost/index.php?app=lunbo获取到的$_SERVER["REQUEST_URI"]为"/index.php?app= ...

  7. 基于FPGA的AES加解密IP

    Programmable AES Encryption/ Decryption IP 可编程AES加解密IP 可编程AES加解密IP提供了加解密算法功能,兼容美国国家标准与技术研究院(NIST)发布的 ...

  8. 我的Spark学习笔记

    一.架构设计 Driver根据用户代码构建计算流图,拆解出分布式任务并分发到 Executors 中去:每个Executors收到任务,然后处理这个 RDD 的一个数据分片子集 DAGSchedule ...

  9. Java反应式编程(1)

    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 前面把Java函数式编程的由来和最主要的核心知识点讲完了.包括比较难懂的Lambda表达式是怎么演变而来的也全部都撸了一遍.Lambda表达式这 ...

  10. 嵌入式-Linux基础操作

    Crtl+Alt+T:调出命令窗口 xrandr:列出分辨率列表 设置窗口的分辨率大小为1280x960:xrandr -s 1280x960 通过命令窗口来执行一段C语言程序: VI工具的使用: ( ...