「MoreThanJava」Day 3:構建程式邏輯的方法
阿新 • • 發佈:2020-07-05
![](https://imgkr.cn-bj.ufileos.com/48d23848-b4b1-4e9d-b1ca-134b62635d33.png)
- **「MoreThanJava」** 宣揚的是 **「學習,不止 CODE」**,本系列 Java 基礎教程是自己在結合各方面的知識之後,對 Java 基礎的一個總回顧,旨在 **「幫助新朋友快速高質量的學習」**。
- 當然 **不論新老朋友** 我相信您都可以 **從中獲益**。如果覺得 **「不錯」** 的朋友,歡迎 **「關注 + 留言 + 分享」**,文末有完整的獲取連結,您的支援是我前進的最大的動力!
# Part 1. 分支結構
![](https://imgkr.cn-bj.ufileos.com/c588aabd-1fa5-45da-89e2-99d2bf18dccd.png)
- 圖片來源:http://www.jituwang.com/vector/201512/569157.html
迄今為止,我們寫的 Java 程式碼都是一條一條語句順序執行的,這種程式碼結構通常稱之為 **順序結構**。
然而僅有順序結構並不能解決所有的問題,比如我們設計一個遊戲,遊戲第一關的通關條件是獲得 `1000` 分,如果分數到達則進入下一關,如果未到達則 ``“Game Over”``:
![](https://imgkr.cn-bj.ufileos.com/83d8302c-e2f7-4aaf-9108-f437b0fbc2bf.png)
這裡就產生了兩個分支,而且這兩個分支只有一個會被執行。類似的場景還有很多,我們將這種結構稱之為 **「分支結構」** 或 **「選擇結構」**。
「是否進入下一關」這樣的決策似乎很小,但是在程式設計中,複雜的決策是由許多這種小的決策組成的。下面是實現是否進入下一關的程式演示:
```java
import java.util.Scanner;
public class Tester {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String answer;
System.out.print("玩家是否達到 1000 分?(Y or N): ");
answer = scan.nextLine();
if ("Y".equals(answer)) {
System.out.println("進入下一關"); // true branch
} else {
System.out.println("Game Over"); // false branch
}
}
}
```
程式首先提醒使用者用單一的字元 `Y` 或 `N` 來回答:
```java
System.out.print("玩家是否達到 1000 分?(Y or N): ");
```
然後使用 `Scanner` 類來獲取使用者的輸入:
```java
answer = scan.nextLine();
```
然後使用 `if` 關鍵字來判斷使用者輸入的字元是否等於 `Y`:
```java
if ("Y".equals(answer))
```
如果相等則進入 `true branch`,否則進入 `false branch`。
> **縮排:**
>
> 這裡 `if` 下方的縮排是為了讓使用者更容易看到程式的邏輯,編譯器將忽略掉這些縮排。
>
> 合理的縮排和程式佈局很重要,沒有適當的距離和縮排,看程式的邏輯有時會稍顯困難。您也期望儘可能清晰地表明程式在做什麼不是嗎?
## if 條件語句
在 Java 中,要構造分支結構可以使用 `if`、`else` 關鍵字。
`if` 語句的基本語法是:
```java
if (條件) {
// 條件滿足時執行的語句
}
```
當條件滿足時,則會執行 `if` 語句中的程式碼塊兒,否則執行 `if` 語句塊後面的程式碼。
例如:
```java
public class Tester {
public static void main(String[] args) {
int n = 70;
if (n >= 60) {
System.out.println("及格了");
}
System.out.println("END");
}
}
```
儘管當 `if` 語句塊只有一行語句時,可以省略花括號 `{}`:
```java
if (n >= 60)
System.out.println("及格了");
```
當這並不是一個好主意。
假設某個時候,突然想給 `if` 語句塊增加一條語句時:
```java
public class Tester {
public static void main(String[] args) {
int n = 50;
if (n >= 60)
System.out.println("及格了");
System.out.println("恭喜你"); // 注意這條語句不是if語句塊的一部分
System.out.println("END");
}
}
```
由於使用縮排格式,很容易把兩行語句都看成 `if` 語句的執行塊,但實際上只有第一行語句是 `if` 的執行塊。
在使用 `git` 這些版本控制系統自動合併時更容易出問題,所以不推薦忽略花括號的寫法。*(事實上,你使用 IDEA 的自動排版程式碼的功能會幫你自動還原成有花括號的寫法,快捷鍵「ctrl + alt + l」)*
## else 語句
`if` 語句還可以編寫一個 `else { ... }`,當條件判斷為 `false` 時,將執行 `else` 的語句塊:
```java
public class Tester {
public static void main(String[] args) {
int n = 70;
if (n >= 60) {
System.out.println("及格了");
} else {
System.out.println("掛科了");
}
System.out.println("END");
}
}
```
修改上面程式碼的 `n` 值,觀察 `if` 條件為 `true/ false` 時,程式執行的語句塊。
注意,`else` 不是必須的。
還可以用多個 `if ... else if ...` 串聯。例如:
```java
public class Tester {
public static void main(String[] args) {
int n = 70;
if (n >= 90) {
System.out.println("優秀");
} else if (n >= 60) {
System.out.println("及格了");
} else {
System.out.println("掛科了");
}
System.out.println("END");
}
}
```
串聯的效果其實相當於:
```java
if (n >= 90) {
// n >= 90為true:
System.out.println("優秀");
} else {
// n >= 90為false:
if (n >= 60) {
// n >= 60為true:
System.out.println("及格了");
} else {
// n >= 60為false:
System.out.println("掛科了");
}
}
```
### 注意順序和臨界條件
在串聯使用多個 `if` 時,要特別注意判斷順序。觀察下面的程式碼:
```java
public class Tester {
public static void main(String[] args) {
int n = 100;
if (n >= 60) {
System.out.println("及格了");
} else if (n >= 90) {
System.out.println("優秀");
} else {
System.out.println("掛科了");
}
}
}
```
執行發現,`n = 100` 時,滿足條件 `n >= 90`,但輸出的不是 `"優秀"`,而是 `"及格了"`,原因是 `if` 語句從上到下執行時,先判斷 `n >= 60` 成功後,後續 `else` 不再執行,因此,`if (n >= 90)` 沒有機會執行了。
正確的方式是按照判斷範圍從大到小依次判斷:
```java
// 從大到小依次判斷:
if (n >= 90) {
// ...
} else if (n >= 60) {
// ...
} else {
// ...
}
```
或者改寫成從小到大依次判斷:
```java
// 從小到大依次判斷:
if (n < 60) {
// ...
} else if (n < 90) {
// ...
} else {
// ...
}
```
使用 `if` 時,還要特別注意邊界條件。例如:
```java
public class Tester {
public static void main(String[] args) {
int n = 90;
if (n > 90) {
System.out.println("優秀");
} else if (n >= 60) {
System.out.println("及格了");
} else {
System.out.println("掛科了");
}
}
}
```
假設我們期望 `90` 分或更高為 `“優秀”`,上述程式碼輸出的卻是 `“及格”`,原因是 `>` 和 `>=` 效果是不同的。
# Part 2. 迴圈結構
![](https://imgkr.cn-bj.ufileos.com/6d223877-5b00-4f9b-a972-c854f8556c0f.png)
- 圖片引用自:https://www.zlovezl.cn/articles/two-tips-on-loop-writing/
順序結構的程式語句只能被執行一次。如果您想要同樣的操作執行多次,就需要使用迴圈結構。
Java 中有三種主要的迴圈結構:
- `while` 迴圈;
- `do...while` 迴圈;
- `for` 迴圈 *(在 Java 5 中還引入了一種主要用於陣列的增強型 `for` 迴圈)*;
## while 迴圈
`while` 是最基本的迴圈,它的結構為:
```java
while ( 布林表示式 ) {
// 迴圈內容
}
```
只要布林表示式為 `true`,迴圈就會一直執行下去。
### 例項
```java
public class Test {
public static void main(String args[]) {
int x = 10;
while (x < 20) {
System.out.println("value of x : " + x);
x++;
}
}
}
```
以上例項編譯執行結果如下:
```console
value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
```
## do...while 迴圈
對於 `while` 語句而言,如果不滿足條件,則不能進入迴圈。但有時候我們需要即使不滿足條件,也至少執行一次。
`do…whil`e 迴圈和 `while` 迴圈相似,不同的是,`do…while` 迴圈至少會執行一次。
```java
do {
// 程式碼語句
} while (布林表示式);
```
**注意**:布林表示式在迴圈體的後面,所以語句塊在檢測布林表示式之前已經執行了。 如果布林表示式的值為 `true`,則語句塊一直執行,直到布林表示式的值為 `false`。
### 例項
```java
public class Test {
public static void main(String args[]) {
int x = 10;
do {
System.out.println("value of x : " + x);
x++;
} while (x < 20);
}
}
```
以上例項編譯執行結果如下:
```console
value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
```
## for 迴圈
雖然所有迴圈結構都可以用 `while` 或者 `do...while` 表示,但 Java 提供了另一種語句 —— `for` 迴圈,使一些迴圈結構變得更加簡單。
`for` 迴圈執行的次數是在執行前就確定的。語法格式如下:
```java
for(初始化; 布林表示式; 更新) {
// 程式碼語句
}
```
關於 `for` 迴圈有以下幾點說明:
- 最先執行初始化步驟。可以宣告一種型別,但可初始化一個或多個迴圈控制變數,也可以是空語句。
- 然後,檢測布林表示式的值。如果為 true,迴圈體被執行。如果為false,迴圈終止,開始執行迴圈體後面的語句。
- 執行一次迴圈後,更新迴圈控制變數。
- 再次檢測布林表示式。迴圈執行上面的過程。
### 例項
```java
public class Test {
public static void main(String args[]) {
for (int x = 10; x < 20; x = x + 1) {
System.out.println("value of x : " + x);
}
}
}
```
以上例項編譯執行結果如下:
```console
value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
```
> 您可以再 IDEA 中快速輸入 `fori` 關鍵字來快速建立 `for` 迴圈的基本結構
## 控制迴圈
### break 關鍵字
`break` 主要用在迴圈語句或者 `switch` 語句中,用來跳出整個語句塊。
`break` 跳出最裡層的迴圈,並且繼續執行該迴圈下面的語句。
#### 例項
```java
public class Test {
public static void main(String args[]) {
int[] numbers = {10, 20, 30, 40, 50};
for (int x : numbers) {
// x 等於 30 時跳出迴圈
if (x == 30) {
break;
}
System.out.print(x);
System.out.print("\n");
}
}
}
```
以上例項編譯執行結果如下:
```console
10
20
```
### continue 關鍵字
`continue` 適用於任何迴圈控制結構中。作用是讓程式立刻跳轉到下一次迴圈的迭代。
在 `for` 迴圈中,`continue` 語句使程式立即跳轉到更新語句。
在 `while` 或者 `do…while` 迴圈中,程式立即跳轉到布林表示式的判斷語句。
#### 例項
```java
public class Tester {
public static void main(String args[]) {
int[] numbers = {10, 20, 30, 40, 50};
for (int x : numbers) {
if (x == 30) {
continue;
}
System.out.print(x);
System.out.print("\n");
}
}
}
```
以上例項編譯執行結果如下:
```console
10
20
40
50
```
# Part 3. 構造程式邏輯
![](https://imgkr.cn-bj.ufileos.com/b00c2ec4-93b4-4569-b006-83328b9f4d30.png)
- 圖片來源:http://www.mzh.ren/machine-learning-3.html
雖然迄今為止我們學習的內容只是 Java 的冰山一角,但是這些內容已經足夠我們來構建程式中的邏輯。
對於程式語言的初學者來說,在學習了 Java 的核心語言元素 *(變數、型別、運算子、表示式、分支結構、迴圈結構等)* 之後,必須做的一件事情就是嘗試用所學知識去解決現實中的問題,換句話說就是鍛鍊自己把用人類自然語言描述的演算法 *(解決問題的方法和步驟)* 翻譯成 Java 程式碼的能力,而這件事情必須通過大量的練習才能達成。
我們在這一 Part 為大家整理了一些經典的案例和習題,希望通過這些例子,一方面幫助大家鞏固之前所學的 Java 知識,另一方面幫助大家瞭解如何建立程式中的邏輯以及如何運用一些簡單的演算法解決現實中的問題。
## 經典的例子
### 題目一:尋找水仙花數
> **說明**:水仙花數也被稱為超完全數字不變數、自戀數、自冪數、阿姆斯特朗數,它是一個 `3` 位數,該數字每個位上數字的立方之和正好等於它本身,*例如:13 + 53+ 33=153*。
```java
public class Tester {
public static void main(String[] args) {
findAllDaffodilNumberAndPrint();
}
/**
* 查詢所有的水仙花數並列印
*/
public static void findAllDaffodilNumberAndPrint() {
for (int num = 100; num < 1000; num++) {
int low = num % 10;
int mid = num / 10 % 10;
int high = num / 100;
// Math.pow(x, 3) 相當於求 x 的 3 次方
if (num == Math.pow(low, 3) + Math.pow(mid, 3) + Math.pow(high, 3)) {
System.out.println(num);
}
}
}
}
```
### 題目二:百錢百雞問題
> **說明**:百錢百雞是我國古代數學家張丘建在《算經》一書中提出的數學問題:雞翁一值錢五,雞母一值錢三,雞雛三值錢一。百錢買百雞,問雞翁、雞母、雞雛各幾何?翻譯成現代文是:公雞 `5` 元一隻,母雞 `3` 元一隻,小雞 `1` 元三隻,用 `100` 塊錢買一百隻雞,問公雞、母雞、小雞各有多少隻?
```java
public class Tester {
public static void main(String[] args) {
getResultAndPrint();
}
/**
* 獲取百錢百雞的結果並輸出
*/
public static void getResultAndPrint() {
for (int cockNum = 0; cockNum < 20; cockNum++) {
for (int henNum = 0; henNum < 33; henNum++) {
int chickNum = 100 - cockNum - henNum;
if (5 * cockNum + 3 * henNum + chickNum / 3 == 100) {
System.out
.println("公雞:" + cockNum + "只, 母雞:" + henNum + "只, 小雞:" + chickNum + "只");
}
}
}
}
}
```
上面使用的方法叫做 **窮舉法**,也稱為 **暴力搜尋法**,這種方法通過一項一項的列舉備選解決方案中所有可能的候選項並檢查每個候選項是否符合問題的描述,最終得到問題的解。
這種方法看起來比較笨拙,但對於運算能力非常強大的計算機來說,通常都是一個可行的甚至是不錯的選擇,而且問題的解如果存在,這種方法一定能夠找到它。
# 要點回顧
1. 分支結構 `if` 和 `else` 的使用和例項;
1. 迴圈結構 `while`、`do...while` 和 `for` 迴圈的使用和例項;
1. 控制迴圈的 `break` 和 `continue` 例項;
1. 構建程式邏輯的練習;
# 練習
## 練習 1:百分之成績轉換成等級製成績
> **要求:**
>
> 1. 如果輸入成績在 `90` 分以上 *(含 `90` 分)* 輸出 `A`;
> 1. `80 ~ 90` 分 *(不含 `90`)* 輸出 `B`;
> 1. `70 ~ 80` 分 *(不含 `80`)* 輸出 `C`;
> 1. `60 ~ 70` 分 *(不含 `70`)* 輸出 `D`;
> 1. `60` 分以下輸出 `E`;
參考答案:
```java
import java.util.Scanner;
public class Tester {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int score = scan.nextInt();
if (score >= 90) {
System.out.println("A");
} else if (score >= 80) {
System.out.println("B");
} else if (score >= 70) {
System.out.println("C");
} else if (score >= 60) {
System.out.println("D");
} else {
System.out.println("E");
}
}
}
```
## 練習 2:輸入三條邊長,如果能構成三角形就計算周長和麵積
參考答案:
```java
import java.util.Scanner;
public class Tester {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
double a = scan.nextDouble();
double b = scan.nextDouble();
double c = scan.nextDouble();
if (a + b > c && a + c > b && b + c > a) {
double perimeter = a + b + c;
System.out.println("三角形周長為:" + perimeter);
double p = (a + b + c) / 2;
double area = Math.sqrt(p * (p - a) * (p - b) * (p - c));
System.out.println("三角形面積為:" + area);
} else {
System.out.println("不能構成三角形!");
}
}
}
```
## 練習 3:列印如下所示的三角形圖案
```console
*
**
***
****
*****
```
```console
*
**
***
****
*****
```
```console
*
***
*****
*******
*********
```
參考答案:
```java
import java.util.Scanner;
public class Tester {
public static void main(String[] args) {
System.out.println("請輸入行數:");
Scanner scanner = new Scanner(System.in);
int row = scanner.nextInt();
for (int i = 0; i < row; i++) {
for (int j = row - i - 1; j < row; j++) {
System.out.print("*");
}
// 換行
System.out.println();
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < row; j++) {
if (j < row - i - 1) {
System.out.print(" ");
} else {
System.out.print("*");
}
}
// 換行
System.out.println();
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < row - i - 1; j++) {
System.out.print(" ");
}
for (int j = 0; j < 2 * i + 1; j++) {
System.out.print("*");
}
// 換行
System.out.println();
}
}
}
```
# 自取資料
## 優秀入門資料選取
1. Introduction to Computer Science using Java - http://programmedlessons.org/Java9/index.html
1. Java零基礎入門教程包含面向物件 - https://study.163.com/course/courseMain.htm?courseId=1003108028
1. 網易雲課堂 - 頂尖中文大學計算機專業課程體系 - https://study.163.com/curricula/cs.htm
1. TeachYourselfCS-CN (自學電腦科學) - https://github.com/keithnull/TeachYourselfCS-CN
1. C語言中文網 Java 入門系列教程 - http://c.biancheng.net/java/10/
1. 廖雪峰 Java 教程 - https://www.liaoxuefeng.com/wiki/1252599548343744
1. 注重動手能力的 Java 教程 - https://how2j.cn/
## 推薦書籍
#### Java 核心技術·卷 I(原書第 11 版)
![](https://imgkr.cn-bj.ufileos.com/1ed33e34-7d6d-4d05-8849-9f60a278726c.png)
**推薦理由:** 這本書在知識體系完整充實的同時,又比《Thinking in Java》暴風式的知識洗禮來得輕鬆,新人入門書籍強烈推薦!
#### 碼出高效:Java開發手冊
![](https://imgkr.cn-bj.ufileos.com/87b25b84-8ecc-4196-980b-3f73811c48e9.png)
**推薦理由:** 阿里系出品。從最基礎的計算機基礎入手,到 Java 的方方面面,加上精美的配圖和通俗易懂的解釋,是非常適合新手閱讀的一本兒關於 Java 的技術書籍。
# 參考資料
1. 《Java 核心技術 卷I》(第11版)
1. Introduction to Computer Science using Java - http://programmedlessons.org/Java9/index.html#part02
1. 菜鳥教程 - https://www.runoob.com/java/
1. C語言中文網 Java 入門系列教程 - http://c.biancheng.net/java/10/
1. Python 100 天從新手到大師 - https://github.com/jackfrued/Python-100-Days
> - 本文已收錄至我的 Github 程式設計師成長系列 **【More Than Java】,學習,不止 Code,歡迎 star:[https://github.com/wmyskxz/MoreThanJava](https://github.com/wmyskxz/MoreThanJava)**
> - **個人公眾號** :wmyskxz,**個人獨立域名部落格**:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長!
![](https://imgkr.cn-bj.ufileos.com/ace97ed9-3cfd-425f-85e5-c1a1e5ca7d3f.png)
非常感謝各位人才能 **看到這裡**,如果覺得本篇文章寫得不錯,覺得 **「我沒有三顆心臟」有點東西** 的話,**求點贊,求關注,求分享,求留言!**
創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文