第三章 选择

课本笔记 第三章

引言

  • 程序可以基于条件决定执行哪些语句

boolean 数据类型

  • boolean数据类型声明一个具有值true或者false的变量
  • Java提供六种关系操作符(relational operator)(也称为比较操作符(comparison operator))
表 3-1 关系操作符
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 Scanner
        Scanner 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(布尔表达式){
      语句(组);
      }
      
  • 流程图是描述算法或者过程的图,以各种盒子显示步骤,并且通过箭头连接它们给出顺序。处理操作显示在这些盒子中,连接它们的箭头代表控制流程。棱形的盒子表示一个布尔类型的条件,矩形盒子代表语句。

  • 省略括号可以让代码更加简短,但是容易产生错误。当你返回去修改略去括号的代码的时候,容易忘记加上括号

程序清单 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出现的歧义

      //看缩进的话是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");
      
    • 两个浮点数值的相等测试

      • 浮点数具有有限的计算精度;涉及浮点数的计算可能引入舍入错误。因此,两个浮点数值的相等测试并不可靠
      final 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;
      else
      	even = 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 integers
        int number1 = (int) (Math.random() * 10);
        int number2 = (int) (Math.random() * 10);

        //2. If number1 <number2,swap number1 with number2
        if (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 result
        if (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));//a
                System.out.println((int)(random.nextDouble()*10 + 10));//b
                System.out.println((int)(random.nextDouble()*+ 51));//c
                System.out.println(random.nextBoolean()?1:0);//d
            /*分析
            a.因为取不到1.0的值,要求0<= i < 20,只需 * 20即可
            b.下限为10, 所以+10,*10
            c.要能够取到50,int强制转换是相当于向下取整,所以+51,*50
            d.使用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 pounds
        System.out.print("Enter weight in pounds: ");
        double weight = input.nextDouble();

        //Prompt the user to enter height in inches
        System.out.print("Enter height in inches: ");
        double height = input.nextDouble();

        final double KILOGRAMS_PER_POUNDS = 0.45359237;//Constant
        final double METERS_PER_INCH = 0.0254;//Constant

        //Compute BMI
        double weightInKilograms = weight * KILOGRAMS_PER_POUNDS;
        double heightInMeters = height * METERS_PER_INCH;
        double bmi = weightInKilograms / (heightInMeters * heightInMeters);

        //Display result
        System.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");
        else
            System.out.println("Obese");
    }
}

示例学习: 计算税率

  • 你可以使用嵌套的if 语句来计算税率
表 3-2 2009年美国国家联邦个人收入所得税税率表
临界税率 单身纳税人 已婚共同纳税人或符合条件的鳏寡 已婚单独纳税人 家庭户主纳税人
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 Scanner
        Scanner input = new Scanner(System.in);

        //Prompt the uesr to enter filing status
        System.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 income
        System.out.print("Enter the taxable income: ");
        double income = input.nextDouble();

        //Compute tax
        double tax = 0;

        if (status == 0) {//Compute tax for single filers
            if (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;
            else
                tax = 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 result
        System.out.println("Tax is " + (int) (tax * 100) / 100.0);
    }
}
  • 对所有的程序都应该先编写少量代码然后进行测试,之后在继续添加更多的代码。这个过程称为递进式开发和测试(incremental development and testing)。这种方法使得调试变得更加容易,因为错误很可能就在你刚刚添加进去的新代码中

逻辑运算符

  • 逻辑操作符!、&&、||、^可以用于产生复合布尔表达式
表 3-3 布尔操作符
操作符 名称 说明
逻辑非
&& 逻辑与
|| 逻辑或
^ 异或 逻辑异或
表 3-4 操作符!的真值表
p !p 举例(假设age = 24,weight = 140)
true false !(age>18) 为false,因为(age>18)为true
false true !(weight==150)为true,因为(weight == 150)为false
表 3-5 操作符&&的真值表
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
表 3-6 或操作符||的真值表
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
表 3-7 异或操作符^的真值表
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 Scanner
        Scanner input = new Scanner(System.in);

        //Receive an input
        System.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 Scanner
        Scanner input = new Scanner(System.in);
        System.out.print("Enter a year: ");
        int year = input.nextInt();

        //Check if the year is a leap year
        boolean isLeepYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);

        //Display the rusult
        System.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 number
        int lottery = (int) (Math.random() * 100);

        //Prompt the user to enter a guess
        Scanner input = new Scanner(System.in);
        System.out.print("Enter your lottery pick(two digits): ");
        int guess = input.nextInt();

        //Get digits from lottery
        int lotteryDigit1 = lottery / 10;
        int lotteryDigit2 = lottery % 10;

        //Get digits from guess
        int guessDigit1 = guess / 10;
        int guessDigit2 = guess % 10;

        System.out.println("The lottery number is " + lottery);

        //Check the guess
        if (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");
        else
            System.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 给出一个程序,提示用户输入一个年份,显示当年的生肖动物

程序清单 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;
        }
    }
}

条件操作

  • 条件操作基于一个条件计算表达式的值

操作符的优先级和结合规则

  • 操作符的优先级和结合规则确定了操作符计算的顺序
表 3-8 操作符优先级表
优先级 操作符
| var++和var--(后置操作符)
| +、-(一元加号和一元减号)、++var、--var(前置操作符)
| (type)(类型转换)
| ! (非)
| *、/、% (乘法、除法和求余运算)
| +、-(二元加号和减号)
| <、<=、>、=>(比较操作符)
| ==、!=(相等操作符)
| ^(异或)
| &&(条件与)
| ||(条件或)
V =、+=、-=、*=、/=、%= (赋值操作符)

调试

  • 调试是在程序中找到和修改错误的过程

  • 调试器都支持以下大部分的有用的特征

    • 一次执行一条语句
      • 调试器允许你一次执行一条语句,从而可以看到每条语句的效果
    • 跟踪进入或者一步运行一个方法
      • 如果一个方法正在被执行,可以让调试器跟踪进入方法内部,并且一次执行方法里面的一条语句,或者也可以让调试器一步运行整个方法。如果你知道方法是正确工作的,应该一次运行整个方法。比如,通常都会一步运行系统提供的方法,比如System.out.println
    • 设置断点
      • 你也可以在一条特定的语句上面设置断点。当遇到一个断点时,程序将暂停。可以设置任意多的断点。当你知道程序错误从什么地方可能开始的时候,断点特别有用。你可以将断点设置在那条语句上,让程序先执行到断点处
    • 显示变量
      • 调试器让你选择多个变量并且显示它们的值。当你跟踪一个程序的时候,变量的内容持续更新
    • 显示调用堆栈
      • 调试器让你跟踪所有的方法调用。当你需要看到程序执行流程的整体过程时,这个特征非常有用
    • 修改变量
      • 一些调试器允许你在调试的过程中修改变量的值。当你希望用不同的示例来测试程序,而又不希望离开调试器的时候,这是非常方便的。
posted @ 2021-10-07 16:01  Wozen  阅读(56)  评论(0)    收藏  举报