Chapter 1 The way of the program(译)
这本书旨在教你学会如何向计算机科学家一样思考。我之喜欢计算机科学家的思考方式是因为他们汇集了数学,工程师和自然科学的思维特性。如数学特性,他们使用公式语句记录思想,如工程师,他们设计的东西,组装部件到系统,evaluating tradeoffs among alternatives。 如科学家,他们观察复杂系统的行为,提出假设,验证猜想。
计算机科学家最重要的技能是解决问题的能力。我的意思是提出问题,创造性地思考解决方案,并提出一种简洁的,准确的解决方法。结果便是,学习解决编程的过程是一种极佳的锻炼解决问题技巧的机会。这也是本章为什么叫做程序之路的原因。
一方面,你将学习如何编程,这是一门非常有用的技能。另一方面,你会用编程作为通往世界尽头的手段。当我们选择继续,尽头会呈现地越来越明晰。
1.1 什么是编程语言?
你将要学习的编程语言是Java,是一门较新的语言(Sun公司在1995年5月提出)。Java是高级语言的一种,其他高级语言有Python,C, C++和Perl等。
你可以从高级语言这个命名知道,对应的名称是低级语言,也成为机器语言或汇编语言。简单来说,计算机只能运行低级语言编写的程序。因此,高级语言编写的程序必须转换成低级语言才能运行。这个转换过程需要花费时间,是高级语言的一个缺点。
当然高级语言的好处巨大的。首先,容易编写是高级语言的一大特性:花更好的时间编写程序,程序容易阅读,并保证正确性。第二,高级语言是可移植的,你可以在不同的计算机上运行程序,程序只需修改小部分甚至无需修改,不像低级语言,他在一台计算机上运行并不能保证在其他的计算机上运行。
基于上述优点,现在的程序几乎都用高级语言编写。只有少部分特殊的应用才会用低级语言。
翻译一个程序的方式有两种: 解释和编译。一个解释器是一个能够阅读高级语言并按照其流程执行的程序。有效地,他逐行翻译程序,交替阅读,执行命令。(边翻译边执行)
编译器是一个将阅读高级语言全部翻译完再执行的程序。(先翻译再执行)通常地你会将编译作为单独的步骤,等编译通过后,在运行编译后的代码。在这种情况中,高级语言程序叫做源代码,而编译后的程序交目标代码或可执行代码。
Java支持上述两种方式。作为翻译成机器语言的代替,Java的编译器生成的是字节码。字节码是像机器语言一样容易解释的,并且是可移植的。因此,Java程序可以在一台机器上编译转化成字节码,再在另一台机子上解释。这种能力是其他高级语言所不具有的。

上述步骤看似有些复杂,但一些大部分开发环境会帮你自动完成这些步骤。你要做的只是: 编写程序,按一下编译按钮等待执行即可。另一方面,了解上述步骤在后台是如何执行地对你是有帮助的,这样当出错时,你能知道哪里出错了。
1.2 什么是程序?
程序是一系列的指令集指定如何执行计算。计算听起来像是数学术语,像是求解一系列等式或求多项式的根,但他也可以是符号执行,如查找替换文档中的文本,或编译一种程序。
指令,又称语句,在各类编程语言中的表现形式各有不同,但以下的几个基本操作大多数语言都遵从:
Input: 输入。从键盘,文件,设备上获取数据。
Output:输出。 在屏幕上显示数据或发送数据,文件给其他设备。
Math: 数学操作。 执行数据操作,如+,*。
Testing: 测试。检查条件,并运行合适序列的语句。
repetition: 重复。重复执行某些操作。
That’s pretty much all there is to it。 你用过的每个程序,不管有多复杂,都是由语句构成。因此,描述编程的一种方式是将一个大而复杂的任务分解成小的子任务直到这些子任务能够被这些基本操作处理。
1.3 什么调试?
出于怪诞的原因,程序错误被称为缺陷,追踪并修正他们的行为称为是调试。
程序会出现以下三类缺陷,我们需要识别并追踪他们:
1.3.1 语法错误
编译器只能识别语法正确的程序,若语法错误,将编译失败。语法指的是:程序的结构及其结构规则。
例如,在英语中,一个句子必须以大写字母开头,以句号结尾。两个语法错误的例子:
1. this sentence contains a syntax error.
2. So does this one
对于大多数读者而言,一些语法错误并不明显。
但对于编译器,语法错误是不可原谅的。在你的程序只有一个错误,编译器将打印该错误信息并退出执行,程序将无法运行。
更糟糕的是,Java的语法规则远多于英语,并且编译器提供的错误信息经常没有帮助。在第一周的编程生涯期间,你将话费大部分时间来追踪检查语法错误。当你拥有丰富经验时,错误将会变少,追踪过程也将变得容易。
1.3.2 运行错误
第二种错误类型是运行错误,这么叫的原因就是他只有在程序运行时刻才会报错。在Java中,运行错误一般发生在解释器解释字节码时发生。
Java是一种安全的语言,这意味着编译器会捕捉很多异常。因此运行错误非常少见,特别是简单程序。
在Java中,运行错误又称为异常,在很多环境中,他们以窗体或对话框的形式将错误信息显示出来。错误信息对于调试很有帮助。
1.3.3 逻辑错误和语义错误
第三种错误类型是逻辑错误或语义错误。如果程序中有逻辑错误,他能编译运行通过而不输出错误信息,但他的运行结果是错误的。
问题在于你编写的程序并不是你想要的程序。程序的语义是错误的。鉴别逻辑错误非常困难,因为你必须检查程序是如何执行的,了解所实现的功能。
1.3.4 实验调试
调试是一项非常重要的技巧。尽管调试是令人沮丧的,但也是编程最有意思的, 最具挑战的,最珍贵的一部分。
调试就像是侦探工作,你必须掌握足够多的细节,根据运行结果来推断执行效果。
调试又像是一门实验科学。一旦你知道哪里出错了,你就修改程序并重试。如果你的假设是正确的,你可以预言修改所得的结果,你向预期的结果又迈进一步。如果你的假设是错误的,你必须重新提出新的方案。正如夏洛克的名言:当你排除了所有的不可能情况,剩下的情况不管是否合理,那必然是真相。
对某些人来说,编程和调试是同一件事情。那是因为,编程就是不断地调试直到获得预期的结果。思想是:你需要不断的运行程序,修改,调试直到你获得一个预期的结果。
比如,Linux操作系统有数千行代码,但他开始只是一个简单程序Linux Torvalds用来探索因特尔的80386芯片。根据Larry Greenfield所说:linus的早期工程只是用来交替输出AAAA,BBBB的程序。最后才成就了Linux。
在后续的几章,我会提更多关于调试和编程实践的建议。
1.4 形式语言和自然语言
自然语言是人们日常交流的语言,如英语,西班牙语等。他们并不是由人类发明的,而是自然形成的。
形式语言是人类为特定应用设计出来的。如数学中的定义就是正式语言,他用来定义数字和书号之间的关系。化学家使用形式语言来表示分子的化学
结构。这最重要的是:
编程语言也是形式语言,为表达计算而设计的。
形式语言有着相当严谨的语法规则。如,3+3=6 是正确的数学语言,而3 $ =则并不正确。H2O是正确的化学表达式,但2Zz缺失错误的。
语法规则分为两类:令牌和结构。令牌是语言的基本元素,像单词,数字,化学元素等。3 $ = 并不成立的原因是$并不是数字。
保持语句结构:令牌是如何被放置的。语句3 $ =从结构上说也是非法的,因为等号不能出现在等式的最右边。相似地,分子式的下标不应该出现在元素的前面,而应该是后面。
当你阅读英语句子或者形式语言的语句时,你需要了解句子的结构,这个过程叫做解析。(解析结构)
尽管形式语言和自然语言有共同的特性,如令牌,结构,句法,语义等,但他们还是有区别的,体现在以下三个方面:
歧义:
自然语言充满歧义,人们通过上下的解析来分析句子表达的正确含义。而形式语言则是明确的,每条语句都只有一个意思,与上下文无关。
冗余:
为了弥补歧义带来的缺陷,人们用自然语言交流时,经常带有冗余的信息。而形式语言没有冗余的信息。
文学性:
自然语言含有丰富的成语和隐喻。形式语言直观表述其观点。
形式语言与自然语言的区别就像是诗歌和散文的区别:
诗歌:
在诗歌中,单词用来表述意思和声音,整个诗歌营造了积极,感情化的氛围。歧义是常见和直白的。
散文:
单词只是表现其内容而结构更有助于理解其内容。
程序:
程序语言的意义是直观和字面的,可以通过分析令牌和结构所解读。
以下是几点关于阅读程序的建议。首先,形式语言的语句远多于自然语言,需要花费更多的时间来阅读和理解。其二,形式语言的结构非常重要,因此从上到下,从左到右的阅读习惯并不适合阅读程序。你需要在脑海中解析程序,识别令牌,解释结构。最后记住细节非常重要。微小的信息像拼写错误,错误的标点,在自然语言中被忽视的信息,在程序中都是至关重要的。
1.5 第一个程序
通常地,编程人员在学习一门新语言写的第一个程序是"Hello World",因为他在屏幕上显示了"Hello World"。在Java中,程序如下:
class Hello {
// main: generate some simple output
public static void main(String[] args) {
System.out.println("Hello, world.");
}
}
例子1 Hello World
这个程序包含了一些初学者不容易懂的特性,但提供了以后的要讨论的大致框架。
Java程序由类定义组成,结构如下:
class CLASSNAME {
public static void main (String[] args) {
STATEMENTS
}
}
这里的CLASSNAME是程序员命名的,例1的类名是Hello。
main是方法,表示一些语句的集合。main函数名比较特殊,他标志着程序开始执行。当程序执行时,入口是main函数的第一条语句,而结束语句时是其最后一条语句。
main中的语句数目可以任意数目,例子中是仅有一条。他是一条输出语句,表示在屏幕上输出一条信息。“print”该词可以表示"在屏幕上显示信息",或"发送信息给打印机"。在本书中,我们不考虑发送信息给打印机的事,我们只关心信息显示的含义。打印语句的结尾处有;
System.out.println是Java包的方法。包是类和方法定义语句的集合。
Java使用{}将语句组合起来。在外层{}是类的定义,而内{}包含main的定义信息。
第三行的//表示注释,表示对程序功能的解释。当编译器遇到//时,他将忽视这一行的所有信息。
浙公网安备 33010602011771号