引言
- 程序可以基于条件决定执行哪些语句
boolean 数据类型
- boolean数据类型声明一个具有值true或者false的变量
- Java提供六种关系操作符(relational operator)(也称为比较操作符(comparison operator))
| Java操作符 | 数学符号 | 名称 | 示例(半径为5) | 结果 |
|---|---|---|---|---|
| < | < | 小于 | radius < 0 | false |
| <= | ≤ | 小于等于 | radius <= 0 | false |
| > | > | 大于 | radius > 0 | true |
| >= | ≥ | 大于等于 | radius >= 0 | true |
| == | = | 等于 | radius == 0 | false |
| != | ≠ | 不等于 | radius != 0 | true |
- 相等的关系操作符是两个等号(==),而不是一个等号(=),后者是指赋值操作符。
- 保存布尔值的变量称为布尔变量(boolean variable)
程序清单 3-1 AdditionQuiz.java
import java.util.Scanner;public class AdditionQuiz {public static void main(String[] args) {int number1 = (int) (System.currentTimeMillis() % 10);int number2 = (int) (System.currentTimeMillis() / 10 % 10);//Create a ScannerScanner input = new Scanner(System.in);System.out.print("What is " + number1 + " + " + number2 + " ? ");int answer = input.nextInt();System.out.println(number1 + " + " + number2 + " = " + answer + " is " +(number1 + number2 == answer));}}
if语句
- if语句是一个构造,允许程序确定执行的可选路径
- 单分支if语句
- 是指当且仅当条件为true时执行一个动作,其语法如下
if(布尔表达式){语句(组);}
- 是指当且仅当条件为true时执行一个动作,其语法如下
- 流程图是描述算法或者过程的图,以各种盒子显示步骤,并且通过箭头连接它们给出顺序。处理操作显示在这些盒子中,连接它们的箭头代表控制流程。棱形的盒子表示一个布尔类型的条件,矩形盒子代表语句。
- 省略括号可以让代码更加简短,但是容易产生错误。当你返回去修改略去括号的代码的时候,容易忘记加上括号
程序清单 3-2 SimpleIfDemo.java
import java.util.Scanner;public class SimpleIfDemo {public static void main(String[] args) {Scanner input = new Scanner(System.in);System.out.print("Enter an integer: ");int number = input.nextInt();if (number % 5 == 0)System.out.println("HiFive");if (number % 2 == 0)System.out.println("HiEven");}}
双分支if - else语句
- if - else 语句根据条件是真或者是假,决定执行的路径
if(布尔表达式){布尔表达式为真时执行的语句(组);}else{布尔表达式为假时执行的语句(组);}
嵌套的if语句和多分支if - else 语句
- if 语句可以在另外一个if语句中,形成嵌套的if语句
常见错误和陷阱
- 忘记必要的括号,在错误的地方结束if语句,将
==错当作=来使用,悬空else分支,是选择语句中常见的错误。if - else语句中重复的语句,以及测试双精度值的相等是常见的陷阱。 - 常见错误:
- 忘记必要的括号
//错误的if(radius >= 0)area = radius * radius * PI;System.out.println("The area " + " is " + area);//正确的if(radius >= 0){area = radius * radius * PI;System.out.println("The area " + " is " + area);}//错误的等价于if(radius >= 0)area = radius * radius * PI;System.out.println("The area " + " is " + area);
- 忘记必要的括号
- 错误地在if行出现分号
//逻辑错误if(radius >= 0);//error{area = radius * radius * PI;System.out.println("The area " + " is " + area);}//等价于if(radius >= 0){ };//error 空的块{area = radius * radius * PI;System.out.println("The area " + " is " + area);}
- 对布尔值的冗余测试
if (even == true)System.out.println("It is even");//等价于 这种更好if(even)System.out.println("It is even");
- 悬空else出现的歧义 ```java //看缩进的话是else与第一个if匹配,但实际上是else和第二个else匹配 int i = 1,j = 2,k = 3;
if (i > j) if(i > k) System.out.println(“A”); else System.out.println(“B”); //等价于 int i = 1,j = 2,k = 3; //这种写法更好,使用了正确的缩进 if (i > j) if(i > k) System.out.println(“A”); else System.out.println(“B”);
- 两个浮点数值的相等测试- 浮点数具有有限的计算精度;涉及浮点数的计算可能引入舍入错误。因此,两个浮点数值的相等测试并不可靠```javafinal double EPSILON = 1E-14;//注意,这里不要空格double x = 1.0 -0.1-0.1-0.1-0.1-0.1;if (Math.abs(x - 0.5) < EPSILON)System.out.println(x + " is approximately 0.5);
- 常见陷阱:
- 简化布尔变量赋值
if(number % 2 == 0)even = true;elseeven = false;//等价于boolean even= number % 2 == 0;
- 简化布尔变量赋值
- 避免不同情形中的重复代码
//代码冗余if(inState){tuition = 5000;System.out.println("The tuition is " + tuition);}else{tuition = 15000;System.out.println("The tuition is " + tuition);}//等价于if(inState){tuition = 5000;}else{tuition = 15000;}System.out.println("The tuition is " + tuition);
产生随机数
- 你可以使用
Math.random()来获得一个0.0到1.0之间的随机double值,不包括1.0
程序清单 3-3 SubtractionQuiz.java
import java.util.Scanner;public class SubtractionQuiz {public static void main(String[] args) {// 1.Generate two random single-digit integersint number1 = (int) (Math.random() * 10);int number2 = (int) (Math.random() * 10);//2. If number1 <number2,swap number1 with number2if (number1 < number2) {int temp = number1;number1 = number2;number2 = temp;}//3. Prompt the student to answer "What is number1 - number2?"System.out.print("What is " + number1 + " - " + number2 + " ? ");Scanner input = new Scanner(System.in);int answer = input.nextInt();//4.Grade the answer and display the resultif (number1 - number1 == answer)System.out.println("You are correct!");else {System.out.println("Your answer is wrong.");System.out.println(number1 + " - " + number2 +" should be " + (number1 - number2));}}}
a.产生一个随机整数i,使得0<= i < 20?b.产生一个随机整数i,使得10<= i < 20?c.产生一个随机整数i,使得0<= i <= 50?d.编写一个表达式,随机返回0或者1。import java.util.Random;public class sa {public static void main(String[] args) {Random random = new Random();for (int i = 0; i < 100; i++) {System.out.println((int)(random.nextDouble()*20));//aSystem.out.println((int)(random.nextDouble()*10 + 10));//bSystem.out.println((int)(random.nextDouble()*+ 51));//cSystem.out.println(random.nextBoolean()?1:0);//d/*分析a.因为取不到1.0的值,要求0<= i < 20,只需 * 20即可b.下限为10, 所以+10,*10c.要能够取到50,int强制转换是相当于向下取整,所以+51,*50d.使用nextBoolean(),在加以三元运算符 ? : ,即可得到答案以上均可再次使用Math.ceil()向上取整方法,具体不在列出*/}}}
示例学习·: 计算身体质量指数
- 你可以使用嵌套的if 语句来编写程序,计算身体质量指数
程序清单 3-4 ComputeAndInterpretBMI.java
import java.util.Scanner;public class ComputeAndInterpretBMI {public static void main(String[] args) {Scanner input = new Scanner(System.in);//Prompt the user to enter weight in poundsSystem.out.print("Enter weight in pounds: ");double weight = input.nextDouble();//Prompt the user to enter height in inchesSystem.out.print("Enter height in inches: ");double height = input.nextDouble();final double KILOGRAMS_PER_POUNDS = 0.45359237;//Constantfinal double METERS_PER_INCH = 0.0254;//Constant//Compute BMIdouble weightInKilograms = weight * KILOGRAMS_PER_POUNDS;double heightInMeters = height * METERS_PER_INCH;double bmi = weightInKilograms / (heightInMeters * heightInMeters);//Display resultSystem.out.println("BMI is " + bmi);if (bmi < 18.5)System.out.println("Underweight");else if (bmi < 25)System.out.println("Normal");else if (bmi < 30)System.out.println("Overweight");elseSystem.out.println("Obese");}}
示例学习: 计算税率
- 你可以使用嵌套的if 语句来计算税率
| 临界税率 | 单身纳税人 | 已婚共同纳税人或符合条件的鳏寡 | 已婚单独纳税人 | 家庭户主纳税人 |
|---|---|---|---|---|
| 10% | $0 ~ $8350 | $0 ~ $16700 | $0 ~ $8350 | $0 ~ $11950 |
| 15% | $8351 ~ $33 950 | $16701 ~ $67900 | $8351~$33950 | $11951~$45500 |
| 25% | $33951 ~ $82 250 | $67901 ~ $137050 | $33951~$68525 | $45501~$117450 |
| 28% | $82251 ~ $171550 | $137051 ~ $208850 | $68526~$104425 | $117451~$190200 |
| 33% | $171551~$372950 | $208851 ~ $372950 | $104426~$186475 | $190201~$372950 |
| 35% | $372951+ | $372951+ | $186476+ | $372951+ |
程序清单 3-5 ComputeTax.java
import java.util.Scanner;public class ComputeTax {public static void main(String[] args) {//Create a ScannerScanner input = new Scanner(System.in);//Prompt the uesr to enter filing statusSystem.out.print("(0-single filer, 1- married jointly or " +"qualifying widow(er),\n2-married separately, 3-head of " +"household) Enter the filing status: ");int status = input.nextInt();//Prompt the user to enter taxable incomeSystem.out.print("Enter the taxable income: ");double income = input.nextDouble();//Compute taxdouble tax = 0;if (status == 0) {//Compute tax for single filersif (income <= 8350)tax = income * 0.10;else if (income <= 33950)tax = 8350 * 0.10 + (income - 8350) * 0.15;else if (income <= 82250)tax = 8350 * 0.10 + (33950 - 8350) * 0.15 + (income - 33950) * 0.25;else if (income <= 171550)tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +(82250 - 33950) * 0.25 + (income - 82250) * 0.28;else if (income <= 372950)tax = 8350 * 0.10 + (33950 - 8350) * 0.15 +(82250 - 33950) * 0.25 + (171550 - 82250) * 0.28 + (income - 171550) * 0.33;elsetax = 8350 * 0.10 + (33950 - 8350) * 0.15 +(82250 - 33950) * 0.25 + (171550 - 82250) * 0.28 +(372950 - 171550) * 0.33 + (income - 372950) * 0.35;} else if (status == 1) {//Left as an exercise//Compute tax for married file jointly or qualifying widow(er)} else if (status == 2) {//Compute tax for married separately//Left as an exercise in Programming Exercise 3.13} else if (status == 3) {////Left as an exercise in Programming Exercise 3.13} else {System.out.println("Error:invalid status");System.exit(1);}//Display the resultSystem.out.println("Tax is " + (int) (tax * 100) / 100.0);}}
- 对所有的程序都应该先编写少量代码然后进行测试,之后在继续添加更多的代码。这个过程称为递进式开发和测试(incremental development and testing)。这种方法使得调试变得更加容易,因为错误很可能就在你刚刚添加进去的新代码中
逻辑运算符
- 逻辑操作符!、&&、||、^可以用于产生复合布尔表达式
| 操作符 | 名称 | 说明 |
|---|---|---|
| ! | 非 | 逻辑非 |
| && | 与 | 逻辑与 |
| || | 或 | 逻辑或 |
| ^ | 异或 | 逻辑异或 |
| p | !p | 举例(假设age = 24,weight = 140) |
|---|---|---|
| true | false | !(age>18) 为false,因为(age>18)为true |
| false | true | !(weight==150)为true,因为(weight == 150)为false |
| p1 | p2 | p1&&p2 | 举例(假设age = 24,weight = 140) |
|---|---|---|---|
| false | false | false | |
| false | true | false | (age>28) && (weight<=140)为false,因为(age>28)为false |
| true | false | false | |
| true | true | true | (age>18) && (weight>=140)为true,因为(age>18)和(weight>=140)都为true |
| p1 | p2 | p1&&p2 | 举例(假设age = 24,weight = 140) |
|---|---|---|---|
| false | false | false | (age>34) || (weight>150)为false,因为(age>34)和(weight>150)都为false |
| false | true | true | |
| true | false | true | (age>18) || (weight<140)为true,因为(age>18)为true |
| true | true | true | 、 |
| p1 | p2 | p1&&p2 | 举例(假设age = 24,weight = 140) |
|---|---|---|---|
| false | false | false | (age>34) ^(weight>140)为false,因为(age>34)和(weight>140)都为false |
| false | true | true | |
| true | false | true | (age>34) ^ (weight>=140)为true,因为(age>34)为false,但是(weight>=140)为true |
| true | true | false |
程序清单 3-6 TestBooleanOperators.java
import java.util.Scanner;public class TestBooleanOperators {public static void main(String[] args) {//Create a ScannerScanner input = new Scanner(System.in);//Receive an inputSystem.out.print("Enter an integer: ");int number = input.nextInt();if (number % 2 == 0 && number % 3 == 0)//与 二者均为真System.out.println(number + " is divisible by 2 and 3.");if (number % 2 == 0 || number % 3 == 0)//或 二者有一个为真即可System.out.println(number + " is divisible by 2 or 3");if (number % 2 == 0 ^ number % 3 == 0)//异或 二者有且仅有一个为真System.out.println(number + " is divisible by 2 or 3, but not both");}}
- 从数学的角度看,表达式1 <= numberOfDaysInAMonth <= 31是正确的。但是,在Java中它是错的,因为1<= numberOfDaysInAMonth得到的是一个布尔值的结果,它是不能和31进行比较的。这里的两个操作数(一个布尔值和一个数值)是不兼容的。正确的Java表达式是:
28 <= numberOfDaysInAMonth && numberOfDaysInAMonth
- 德摩根定律是以印度出生的英国数学家和逻辑学家奥古斯都·德·摩根(1806-1871)来命名的。这个定律可以用来简化表达式。定义表述如下:
!(condition1 && condition2) is the same as!(condition1 || condition2)!(condition1 || condition2) is the same as!(condition1 && condition2)
示例学习:判定闰年
- 如果某年可以被4整除而不能被100整除,或者可以被400整除,那么这一年就是闰年
程序清单 3-7 LeapYear.java
import java.util.Scanner;public class LeapYear {public static void main(String[] args) {//Create a ScannerScanner input = new Scanner(System.in);System.out.print("Enter a year: ");int year = input.nextInt();//Check if the year is a leap yearboolean isLeepYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);//Display the rusultSystem.out.println(year + " is a leap year? " + isLeepYear);}}
示例学习:彩票
- 彩票程序设计随机数、比较数字各位,以及运用布尔操作符
程序清单 3-8 Lottery.java
import java.util.Scanner;public class Lottery {public static void main(String[] args) {//Generate a lottery numberint lottery = (int) (Math.random() * 100);//Prompt the user to enter a guessScanner input = new Scanner(System.in);System.out.print("Enter your lottery pick(two digits): ");int guess = input.nextInt();//Get digits from lotteryint lotteryDigit1 = lottery / 10;int lotteryDigit2 = lottery % 10;//Get digits from guessint guessDigit1 = guess / 10;int guessDigit2 = guess % 10;System.out.println("The lottery number is " + lottery);//Check the guessif (guess == lottery)System.out.println("Exact match: you win $10,000");else if (guessDigit2 == lotteryDigit1 && guessDigit1 == lotteryDigit2)System.out.println("Match all digits: you win $3,000");else if (guessDigit1 == lotteryDigit1 || guessDigit1 == lotteryDigit2|| guessDigit2 == lotteryDigit1 || guessDigit2 == lotteryDigit2)System.out.println("Match one digit: you win $1,000");elseSystem.out.println("Sorry, no match");}}
switch语句
- switch语句基于变量或者表达式的值来执行语句
- 不要忘记在需要的时候使用break语句。一旦匹配其中一个case,就从匹配的case处开始执行,直到遇到break语句或到达switch语句的结束。这种现象称为
落空行为(fall-through behavior)(也称为switch穿透行为)。例如,下列代码为周一到周五显示Weekdays,为周日和周六显示Weekends。 - 为了避免程序设计错误,提高代码的可维护性,如果刻意省略break,在case子句后添加注释是一个好的做法
- year % 12 确定生肖。1900属鼠,因为1900 % 12 为4。程序清单 3-9 给出一个程序,提示用户输入一个年份,显示当年的生肖动物
- 不要忘记在需要的时候使用break语句。一旦匹配其中一个case,就从匹配的case处开始执行,直到遇到break语句或到达switch语句的结束。这种现象称为
程序清单 3.9 ChineseZodiac.java
import java.util.Scanner;public class ChineseZodiac {public static void main(String[] args) {Scanner input = new Scanner(System.in);System.out.print("Enter a year:");int year = input.nextInt();switch (year % 12) {case 0:System.out.println("monkey");break;case 1:System.out.println("rooster");break;case 2:System.out.println("dog");break;case 3:System.out.println("pig");break;case 4:System.out.println("rat");break;case 5:System.out.println("ox");break;case 6:System.out.println("tiger");break;case 7:System.out.println("rabbit");break;case 8:System.out.println("dragon");break;case 9:System.out.println("snake");break;case 10:System.out.println("horse");break;case 11:System.out.println("sheep");break;}}}
条件操作
- 条件操作基于一个条件计算表达式的值
操作符的优先级和结合规则
- 操作符的优先级和结合规则确定了操作符计算的顺序
| 优先级 | 操作符 |
|---|---|
| | | var++和var—(后置操作符) |
| | | +、-(一元加号和一元减号)、++var、—var(前置操作符) |
| | | (type)(类型转换) |
| | | ! (非) |
| | | *、/、% (乘法、除法和求余运算) |
| | | +、-(二元加号和减号) |
| | | <、<=、>、=>(比较操作符) |
| | | ==、!=(相等操作符) |
| | | ^(异或) |
| | | &&(条件与) |
| | | ||(条件或) |
| V | =、+=、-=、*=、/=、%= (赋值操作符) |
调试
- 调试是在程序中找到和修改错误的过程
- 调试器都支持以下大部分的有用的特征
- 一次执行一条语句
- 调试器允许你一次执行一条语句,从而可以看到每条语句的效果
- 跟踪进入或者一步运行一个方法
- 如果一个方法正在被执行,可以让调试器跟踪进入方法内部,并且一次执行方法里面的一条语句,或者也可以让调试器一步运行整个方法。如果你知道方法是正确工作的,应该一次运行整个方法。比如,通常都会一步运行系统提供的方法,比如System.out.println
- 设置断点
- 你也可以在一条特定的语句上面设置断点。当遇到一个断点时,程序将暂停。可以设置任意多的断点。当你知道程序错误从什么地方可能开始的时候,断点特别有用。你可以将断点设置在那条语句上,让程序先执行到断点处
- 显示变量
- 调试器让你选择多个变量并且显示它们的值。当你跟踪一个程序的时候,变量的内容持续更新
- 显示调用堆栈
- 调试器让你跟踪所有的方法调用。当你需要看到程序执行流程的整体过程时,这个特征非常有用
- 修改变量
- 一些调试器允许你在调试的过程中修改变量的值。当你希望用不同的示例来测试程序,而又不希望离开调试器的时候,这是非常方便的。
- 一次执行一条语句
