琐碎的想法(五)for 的前世今生
for
起因
记得大学上C语言的课,第一次遇到的问题就是循环结构里面的 for
。
选择结构的 if
非常易懂,和日常生活的判断没有区别。
循环结构的 while
同样比较好理解。
本质上是一个判断
- 如果为真,继续循环。
- 如果不假,则退出循环。
而 for
会稍微复杂一些。
for (init-expr; test-expr; update-expr)
body-statement
- 初始化表达式只执行一次
- 判断表达式执行
- 判断为真执行循环体
- 判断为假退出循环体
- 执行更新表达式
在实际的语义等同于(唯一区别是init-expr一个是内部变量,一个是外部变量)
init-expr
while (test-expr) {
body-statement
update-expr
}
那么我们为什么要设计一个不那么好理解的循环结构呢?
因为这时候才入了编程的门————抽象,以及约定。
如果我们再往底层挖,会发现在汇编语言中是不存在while
、for
关键字的。
最开始的程序总是从左到右,从上到下一条路走到黑的。
后面编程人员意识到编写重复的代码过于麻烦才创造了 loop
。
所以最开始需要人工写一个for或者while循环。
while
好理解在于和自然语言(英语)完全符合。
当 条件满足 时, {
执行 流程;
}
而 for
循环的好处在于规范了 while
的使用。
- 初始化语句(init-expr)一般只用于循环,所以放在内部,便于回收变量。
- 循环条件(test-expr)一般配合更新语句一起使用(update-expr),实现循环有限次数。
- 三者的拆分使编写大段的循环或者嵌套循环时,更易读。
// 传统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 循环的出现也意味着编程人员开始在意的不仅仅是功能,而且看重可读性。
然而这并不会被满足。
之后还出现了
- 增强
for
,部分语言的for-each,for...in
。 lamdba
表达式中的forEach()
方法。
注意:以下按 Java 实现的 foreach 举例。(其他编程语言不太熟悉)
增强 for
foreach
的规则
- 所有使用
foreach
的集合都必须实现Iterable
接口 - 通过
iterator()
获取iterator
对象 - 通过
iterator.hasNext()
判断是否存在元素。 - 通过
iterator.next()
获取下一个元素。 - 通过
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
来说,好处是更加简单,符合直觉。
- 无需判断集合个数和中间变量减少代码出错可能性,统一通过
hasNext()
处理。 - 不用分析每个集合类如何获取元素,统一通过
next()
处理。 - 通过语法糖隐藏了
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()的好处显而易见。
- 代码量比
foreach
更少,只关注遍历元素,甚至连元素类型都可以省略。 - 使用了方法引用后更进一步,我们关注的是这个集合执行了哪些操作,遍历每一次的含义在forEach()的方法已经体现了,甚至不需要写遍历的元素。
总结
可以看出,编程人员一直追寻的是更简单,更易读的代码。
- 他们不满足于汇编语言一遍遍的写同一行代码,创造了 while
- 不满足于 复杂或多层 while 的不可读, 创造了 for
- 不满足于 for 循环每一次定义的中间变量,创造了 foreach
- 不满足于 foreach 需要循环每一次的元素,利用了lamdba 的 Consumer, 去掉了元素。
琐碎的想法(五)for 的前世今生的更多相关文章
- Python-装饰器(语法糖)上下五千年和前世今生
装饰器上下五千年和前世今生,这里我们始终要问,装饰器为何产生?装饰器产生解决了什么问题?什么样的需求推动了装饰器的产生?思考问题的时候,始终要问,为什么要这样,而不是那样或者其他样.这里我不先说,也不 ...
- 琐碎的想法(三)对Java的批评的看法
编写本文的目的 在大环境下,Java是一个饱受争议的语言,一方面在工程上它的流行程度非常高:另一方面,越是资深的软件工程师就越容易对这个语言感到不满. 在这种情况下,博主希望每一个Java程序员能够耐 ...
- 《principles of model checking》中的离散时间马尔科夫链
<principles of model checking>中的离散时间马尔科夫链 说明:此文为我自学<principles of model checking>第十章内容的笔 ...
- Angular2+ 使用 Protractor 与 Modify Header Value (HTTP Headers) 插件 完成 Windows Authorization 验证
入职新公司第二周,接到了一个E2E测试的任务,两天的时间把所有的测试条件都写完了,结果剩下三天都卡在了Windows Authorization验证这里. 先说一下公司项目Authorize的逻辑 第 ...
- 一个想法(续五):IT联盟创业计划:现阶段进度公示、疑问解答及进行中的计划
前言: 首先今天是元宵节,先祝大伙元宵节快,单纯的快乐! 然后看看开展中的计划: IT联盟创业计划众筹发起:一个想法(续三):一份IT技术联盟创业计划书,开启众筹创业征程 IT联盟创业计划众筹进度:一 ...
- Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介
Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...
- JVM(五)垃圾回收器的前世今生
全文共 2195 个字,读完大约需要 8 分钟. 如果垃圾回收的算法属于内存回收的方法论的话,那本文讨论的垃圾回收器就属于内存回收的具体实现. 因为不同的厂商(IBM.Oracle),实现的垃圾回收器 ...
- JavaScript的前世今生
和CSS一样,JavaScript在各浏览器下并非完全一致,它所带来的兼容性问题时常困扰着我们,以至于现在“能否处理流行浏览器的兼容性问题”成为了检验一个程序员是否合格的标准之一.了解JavaScri ...
- JavaScript 异步编程的前世今生(上)
前言 提到 JavaScript 异步编程,很多小伙伴都很迷茫,本人花费大约一周的业余时间来对 JS 异步做一个完整的总结,和各位同学共勉共进步! 目录 part1 基础部分 什么是异步 part2 ...
- MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信
MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...
随机推荐
- flutter系列之:builder为构造器而生
目录 简介 Builder StatefulBuilder LayoutBuilder 总结 简介 flutter中有很多种Builder,虽然所有的builder都是构造器,但是不同的builder ...
- Linux基础_2_bash功能
查看当前shell:echo $SHELL 查看可用shell:cat /etc/shells 命令行编辑 光标跳到行首:Ctrl+a 光标跳到行尾:Ctrl+e 以单词为单位快速跳转光标:Ctr ...
- flutter系列之:flutter中可以建索引的栈布局IndexedStack
目录 简介 IndexedStack简介 IndexedStack的使用 总结 简介 之前我们介绍了一个flutter的栈结构的layout组件叫做Stack,通过Stack我们可以将一些widget ...
- python求列表均值,方差,标准差
import numpy as np a = [1,2,3,4,5,6] #求均值 a_mean = np.mean(a) #求方差 a_var = np.var(a) #求标准差 a_std = n ...
- 2.asyncio快速上手
事件循环:可以理解成一个死循环,去检测并执行某些代码 import asyncio # 去生成或者获取一个事件循环 loop = asyncio.get_event_loop() # 将任务放到事 ...
- 7.httpie
可以使用curl或httpie测试我们的服务器.Httpie是用Python编写的用户友好的http客户端 安装:pip3 install httpie #get请求示例 输入命令:http ht ...
- 【MySQL】03_数据类型
MySQL 中的数据类型 类型 类型举例 整数类型 TINYINT.SMALLINT.MEDIUMINT.INT(或INTEGER).BIGINT 浮点类型 FLOAT.DOUBLE 定点数类型 DE ...
- 快速创建软件安装包-ClickOnce
大家好,我是沙漠尽头的狼. .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台. 今天介绍使用ClickOnce制作软件安装包,首先我们先了解什么是ClickOne. 1. 什么是Click ...
- 编码工具使用(go语言)
1.课程介绍 Git基础课程和实操 Goland介绍以及常用快捷键使用 Go delve 调试 你想要的linux 这里都有 2.版本控制工具介绍 原始的版本控制 修改文件,保存文件副本 版本控制的起 ...
- nm命令解释
nm命令参数解释 -A 或-o或 --print-file-name:打印出每个符号属于的文件-a或--debug-syms:打印出所有符号,包括debug符号-B:BSD码显示-C或--demang ...