[笔记] 疯狂JAVA讲义(第3版)第4章 流程控制与数组

简介: [笔记] 疯狂JAVA讲义(第3版)第4章 流程控制与数组

第4章 流程控制与数组

4.1 顺序结构

从上往下执行。没有流程控制的情况下,代码从第一行一直往下执行到最后一行,

4.2 分支结构

Java提供两种常见的分支结构:if语句和switch语句。

4.2.1 if条件语句

if语句使用布尔表达式或布尔值作为分支条件进行分支控制。if语句有3中形式:


if( expression){ //如果条件成立,则执行语句
statement...
}

2.

if(expression){ //如果条件成立,则执行语句
statement...
}
else{ //否则,执行else中语句
statement...
}

3

if(expression){ //如果条件成立,则执行语句
statement...
}
else if(expression){ //否则,如果下一个if成立执行else if中语句
statement...
}
//...可以有0个或多个else if语句
else{ //最后的else也可以省略
statement...
}

花括号括起来的部分作为代码块,将多行代码构成整体。

为了可读性和减少错误,建议if else语句中使用花括号,即使代码块只有一行。

@if else 的逻辑错误

public class IfErrorTest

{

  public static void main(String[] args){
  int age = 45;
  if(age>20){
  System.out.println("青年");
  }
  else if(age>40){
  System.out.println("中年");
  }
  else if(age>60){
  System.out.println("老年"); 
  }
  } 
}

表面上没有问题,但是案例的45岁经过if(age>20)时会输出青年。

应该修改顺序,

if(age>60) //老年

else if(age>40)//中年

else if(age>20)//青年

在使用if else 时,有一条基本规则,应该优先处理包含范围小的条件。比如age>60和age>20,应该先处理范围较小的age>60。

4.2.2 Java 7 增强后的switch语句

switch语句由一个控制表达式和多个case标签组成。

switch的控制表达式只能是byte,short,char,int四个整数型,枚举、String类型(Java7开始允许)

switch语法:

switch(expression)
{
case condition1:
statemet;
break;
}
case condition2:
{
statemet;
break;
}
...
default:
{
statemet;
}

执行先对expression求值,然后依次匹配condition1、condition2、…遇到匹配的就执行对应的执行体。如果都不匹配,则执行default。

由于case标签使代码块非常清晰,可以省略花括号。

@注意不要漏写break,不然一遇到相等的值,程序就会一直执行完标签后面的所有语句。例如下面的例子,如果去掉break,程序输出夏天 秋天 冬天 季节输入错误。

例:

public class StringSwitchTest
{
public static void main(String\[\] args)
{
String season = "夏天";
switch(season)
{
  case "春天":
  System.out.println("春天");
  break;
  case "夏天":
  System.out.println("夏天");
  break;
  case "秋天":
  System.out.println("秋天");
  break;
  case "冬天":
  System.out.println("冬天");
  break;
  default"
  System.out.println("季节输入错误");

4.3 循环结构

在满足条件时,反复执行一段代码(循环体)。

在执行循环体时,需要在某些时候将条件改为假,否则就会一直执行循环体,形成死循环。

循环语句可能包含4个部分:

初始化,循环条件,循环体,迭代语句。

4.3.1 while循环

while语句语法

[init_statement]
while(expression)
{
statement;
[iteration_statement];
}

例:

public class WhileTest
{
public static void main(String[] args)
{
int count =0;
while(count<10)
{
System,out.println(count);
}
System.out.println("循环结束!");
}
}

@while陷阱 while后面紧跟一个;时,while后面的代码块和while没有关系。

4.3.2 do while

do while和while的区别是do while是先do,在判断

[init]
do{
statement;
[iteration_statement];
}while(expression);

do while的循环条件后面必须有一个分号,表明循环结束。

4.3.3 for循环

for循环是更加简洁的循环语句,大部分情况下,都可以使用for循环。

for([init_statemnet]; [test_expression;[iteration_stetement])
{
statement
}

在执行循环前,先执行初始化语句init_stetement;

每次循环前,先计算test_expression的值,如果true,则执行循环体,然后执行循环迭代语句。


@for循环的循环迭代语句没有和循环体放在一起,因此即使循环体遇到continue结束本次循环,循环迭代语句也会执行。这是while、do while语句不能做到的。

例:for循环

public static void main(String[] args){
for(int count =0;count<10;count++){
System.out.println(count);
}
System.out.println("循环结束!");
}

4.3.4 循环嵌套

把一个循环放入另一个循环体内,就可以形成循环嵌套。

for(int i=0;i<5;i++){
for(int j=0;j<3;j++){
System.out.println("i="+i+"j="+j);
}

4.4 控制循环结构

4.4.1 break结束循环

break用于完全结束一个循环,跳出循环体。

@break不仅可以结束其所在的循环,还可以直接结束外层循环,此时需要break后面跟一个标签,这个标签用于标识外层循环。

outer:
for(int i=0;i<5;i++){
for(int j=0;j<3;j++){
Suytem.out.println("i="+i+"j="+j);
if(j==1){
break outer;
}
}

4.4.2 使用continue忽略本次循环剩下语句

@与break类似,continue也可以跟一个标签,忽略标识循环的剩下语句,重新开始下一次循环。

4.4.3 使用return结束方法

return的功能是结束一个方法,如果循环在一个方法中,使用return结束方法,循环也随之结束。

4.5 数组类型

4.5.1 理解数组:数组也是一种类型

Java要求数组的数组元素具有相同的数据类型。

int[] 也是一种类型。

4.5.2 定义数组

type[] arrayName;

type arrayName[];

推荐第一种格式。

数组是一种引用类型的变量,定义时仅仅定义了一个引用变量,(也就是定义了一个指针),还没有指向有效内存。

只有初始化时后才能使用。

4.5.3 数组的初始化

1.静态初始化

arrayName = new type[] {element1,element2,…};

简化的格式

type[] arrayName = {element1,element2,…};

2.动态初始化

只指定数组长度,由系统指定初始值。

arrayName = new type[length];

@不要同时静态初始化和动态初始化。不要即指定长度,又同时指定初始值。

4.5.4 使用数组

访问元素arrayName[index]

索引是从0开始的。

数组提供了length属性,表示数组长度。可以利用length遍历数组

for(int i=0;i<prices.length;i++){
System.out.println(prices[i]);
}

4.5.5 foreach循环

用于遍历数组和集合。

for(type variableName : array|collection)
{
//varivableName自动迭代访问每个元素
}

例子:

//

String[] books = {"Bo1","Bo2"};
for(String book : books)
{
System.out,println(book);
}

@for each循环不能改变数组元素的值,因此不要用foreach进行赋值。

4.6 深入数组

4.6.1 内存中的数组

数组引用变量是一个引用,这个引用变量可以指向任何有效内存,然后访问数组元素。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LVPO4uLo-1588335970117)(media/image1.png)]{width=“5.433566272965879in” height=“3.0264884076990377in”}


只要类型兼容,可以让一个数组变量指向另一个实际的数组,这种操作会让人产生数组长度可变的错觉,但其实数组没变,只是引用变量指向另一个数组。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d38TXVTh-1588335970119)(media/image2.png)]{width=“4.286713692038496in” height=“4.588170384951881in”}

4.6.2 基本类型数组的初始化

int [] iArr;
iArr = new int[5];
for(int i=0;i<iArr.length; i++){
iArr[i] = i+10;
}

4.6.3 引用类型数组的初始化

数组元素是引用时,情况变得复杂。

//Person类
//定义Person数组
Person[] students;
students = new Person[2];
//创建Person实例zhang
Person zhang = new Person();
zhang,age = 15;zhang,height = 158;
//创建Person实例Lee
Person lee = = new Person();
lee.age = 16;lee.height = 160;
//赋值给数组元素
student[0] = zhang;
student[1] = lee;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLpVP9qC-1588335970123)(media/image3.png)]{width=“4.083916229221347in” height=“2.094316491688539in”}

4.6.4 “没有多维数组”

Java提供了支持多维数组的语法,但从数组底层来说,只有一维数组。

int[][] arrName; //二维数组的定义

它的本质还是一维数组,数组元素也是引用,元素保存的引用指向一维数组。

接着对二维数组进行初始化:

arrName = new type[length][];

同样可以当成是一维数组的初始化,这个一维数组的元素是引用类型(数组类型)的。

4.6.5 Java8增强的工具类 Arrays

Arrays类包含一些static方法可以直接操作数组。

二分查找binarySearch

复制数组 copyOf

判断相等equals

填充数组fill

排序 sort

转换字符串 toString

int binarySearch(type[] a, type key): 二分查找key在a数组出现的索引,如果不包含key,则返回负数。要求数组元素已经升序排列。


int binarySearch(type[] a,int fromIndex, int toIndex, type key) 只搜索从fromIndex到 toIndex的元素


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hx3uaxsu-1588335970128)(media/image4.png)]{width=“8.139860017497814in” height=“4.137016622922134in”}


@Arrays类 ,使用需要import java.util.Arrays类。


java8 为Arrays类增加的工具方法:


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-61ThhsbZ-1588335970129)(media/image5.png)]{width=“7.311807742782152in” height=“4.916083770778653in”}


@parallel代表并行

Arrays类使用举例:

import java.util.Arrays;
public class ArraysTest
{
public static void main(String[] args){
int [] a = new int[]{3,4,5,6};
int [] a2 = new int[]{3,4,5,6};
System.out.println("a和a2是否相等:"+Arrays.equals(a,a2));
int []b = Arrays.copyOf(a,6);
System.out.println("a和b是否相等:"+Arrays.equals(a,b));
System.out.println("b数组元素:"+Arrays.toString(b));
Arrays.fill(b,2,4,1);
System.out.println("b数组元素:"+Arrays.toString(b));
Arrays.sort(b);
System.out.println("b数组元素:"+Arrays.toString(b));
}
}

Arrays类新增方法举例:

import java.util.*;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
public class ArraysTest2 {
public static void main(String[] args) {
int[] arr1 = new int[] { 3, -4, 25, 16, 30, 18 };
Arrays.parallelSort(arr1);
System.out.println(Arrays.toString(arr1));
int[] arr2 = new int[] { 3, -4, 25, 16, 30, 18 };
Arrays.parallelPrefix(arr2, new IntBinaryOperator() {
public int applyAsInt(int left, int right) {
return left * right;
}
});
System.out.println(Arrays.toString(arr2));
int[] arr3 = new int[5];
Arrays.parallelSetAll(arr3,new IntUnaryOperator(){
@Override
public int applyAsInt(int operand) {
return operand*5;
}
});
System.out.println(Arrays.toString(arr3));
}
}

4.6.6 数组的应用举例

如果程序中有多个类型相同的变量,且它们具有逻辑的整体性,则可以将它们定义成一个数组。

例如,开发一个工具函数:将一个浮点数转换成人民币读法字符串,这个程序就很需要使用数组,

思路是将浮点数分成整数和小数部分,整数部分使用整数强制转换,小数部分用浮点数-整数部分即可。

整数部分需要考虑中国的数字习惯,4位一节,1个4位数字可以转换成几千几百几十几。

除此之外,还可以利用二维数组实现五子棋,连连看,俄罗斯方块等小游戏。

//五子棋,仅实现棋盘,胜负判定未实现

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.*;
public class Gobang
{
//棋盘大小
private static int BOARD_SIZE = 15;
//二维数组当棋盘
private String[][] board;
//初始化棋盘
public void initBoard(){
board = new String[BOARD_SIZE][BOARD_SIZE];
for(int i=0;i<BOARD_SIZE;i++){
for(int j=0;j<BOARD_SIZE;j++){
board[i][j] = "+";
}
}
}
//控制台输出棋盘

public void printBoard(){
for(int i=0;i<BOARD_SIZE;i++){
for(int j=0;j<BOARD_SIZE;j++){
System.out.print(board[i][j]);
}
System.out.print(\"\n");
}
}

public static void main(String[] args) throws Exception{
Gobang gb = new Gobang();
gb.initBoard();
gb.printBoard();
//获取键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = null;
while(( inputStr=br.readLine())!=null){
String[] posStrArr = inputStr.split(",");
int xPos = Integer.parseInt(posStrArr[0]);
int yPos = Integer.parseInt(posStrArr[1]);
gb.board[yPos-1][xPos-1] = "#";
gb.printBoard();
System.out.println("请输入下棋的坐标: x,y");
}
}
}

附录 本章练习

1.使用循环打印九九乘法表

//九九乘法表
package ch4;

public class Test1 {
  public static void main(String[] args) {
    for(int i=1;i<=9;i++) {
      for(int j=1;j<=i;j++) {             System.out.print(i+"*"+j+"="+i*j+" ");
      }
      System.out.print("\n");
    }
  } 
}


2.使用循环输出等腰三角形。

//打印rows行的等腰三角形
package ch4;

public class Test2 {
  public static void main(String[] args) {
    final int rows = 4;
    for(int i=1;i<=rows;i++) {
      for(int j=0;j<rows-i;j++) {
        System.out.print(" ");
      }
      for(int j=0;j<2*i-1;j++) {
        System.out.print("*");
      }
      System.out.print("\n");
    }
  }
}

3.打印近似圆

//画圆
package ch4;

public class Test3 {
  public static void main(String[] args) {
    int r = 10 ;//半径
    for(int y=0;y<=2*r;y+=2) { //y+=2,如果是y++的话就会(因为精度)很难看
      int x1 = r-getX(r,y);
      int x2 = r+getX(r,y);
      for(int j=0-r;j<x1;j++) {
        System.out.print(" ");
      }
      System.out.print("*");
      for(int j=x1;j<x2;j++) {
        System.out.print(" ");
      }
      System.out.print("*");
      System.out.print("\n");

    }

  }
  public static int getX(int r,int y) {
    double tempX;
    tempX = Math.sqrt(r*r - (y-r)*(y-r));
    return (int)Math.round(tempX); 

  }
}

4.按字节截取字符串的子串。类似String类的substring()。

感觉这个题目有问题,略过

5.编写一个程序,将浮点数转换成人民币读法字符串,精确到分且不超过12位。例如。将1006.333转换为壹仟零陆元叁角叁分

重点是转换规律是每4位一转,然后根据位置加上元/万/亿。

另一个易错点是零的处理,连续零和末尾零以及全零数。

package ch4;
public class Test5 {
  public static String[] hanArr= {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
  public static String[] unitArr= {"十","百","千"};
  public static  String divide(double num) {
    long zheng = (long )num;//整数部分
    long xiao = Math.round((num-zheng)*100); //保留两位小数
    return new String(zheng+"#"+xiao);
  }
  //将4位及4位以内数字字符串转换成人民币读法
  public static String trans4(String s) {
    int len = s.length();
    if(len>4&&len<1) {
      System.out.println("传入参数错入,应该传入1-4位的数字字符串");
      return "";
    }
    String tmp = s;
    String result = "";
    if("0000".equals(tmp)||"000".equals(tmp)||"00".equals(tmp)||
        "0".equals(tmp)){
      return result = hanArr[0];
    }
    //去除前面的0
    while(tmp.charAt(0)=='0'&&len>1) {
      tmp = tmp.substring(1,len);
      len = len-1;
    }
    //转换...
    for(int i=0;i<len;i++) {
      int n = tmp.charAt(i)-48;
      //不为0且不是最后一位,直接转为数字+单位
      if( n !=0 && (i!=len-1)) {
        result+= hanArr[n]+unitArr[len-2-i];
      }else if(n==0) {
        //判断连续0,前面不是0时加'零',有连续的0过就跳过,末尾的0也跳过
        if((tmp.charAt(i-1)-48)!=0 && i!=len-1) {
          result+=hanArr[0];
        }     
      }else if(n!=0&&(i==len-1)) {
        result+=hanArr[n];
      }   
    }
    //末尾零,去掉
    if(result.charAt(result.length()-1)=='零') {
      result = result.substring(0,result.length()-1);
    }
    return result;
  }
  public static String transAll(String s) {
    String result = ""; 
    //4位数以内
    if(s.length()<=4) {
      result = trans4(s);
    }
    //4位数以上8位数以内
    else if(s.length()<=8)
    {
      String s1 = trans4(s.substring(0,s.length()-4));//高位
      String s2 = trans4(s.substring(s.length()-4));//低位
      if("零".equals(s2)) {
        s2="";
      } 
      result = s1 +"万"+ s2;
    }
    else if(s.length()<=12) 
    {
      String s1 = trans4(s.substring(0,s.length()-8));//高位
      String s2 = trans4(s.substring(s.length()-8,s.length()-4)) ;//低位
      String s3 = trans4(s.substring(s.length()-4));    //最低位
      result += s1 +"亿";
      if(!"零".equals(s2)) {
        result += s2+"万";
      }
      if(!"零".equals(s3)) {
        result += s3;
      }
    }
    return result;
  } 
  public static void main(String[] args) {
    double num = 12301234000.11;
    String snum = divide(num);
    String zheng = snum.substring(0, snum.indexOf("#"));
    String xiao = snum.substring(snum.indexOf("#")+1);  
    //小数部分简单, 直接写在这里了
    String han_xiao ="";
    if(xiao.length()==1) {
      char c=xiao.charAt(0);
      han_xiao = hanArr[(c-48)]+"角";    
    }else if(xiao.length()==2) {
      char c=xiao.charAt(0);
      han_xiao += hanArr[(c-48)]+"角";   
      c = xiao.charAt(1);
      han_xiao += hanArr[(c-48)]+"分";   
    }
    System.out.println(transAll(zheng)+" "+han_xiao);
  }
}

6.控制台五子棋

/*实现了双人对战,未处理非法输入,
因为没找到合适的字符棋盘有点难看
*/
package ch4;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.*;

public class Gobang
{
    private static int BOARD_SIZE = 15;     //棋盘大小
    private String[][] board;         //二维数组当棋盘
    //初始化棋盘
    public void initBoard(){
        board = new String[BOARD_SIZE][BOARD_SIZE];
        for(int i=0;i<BOARD_SIZE;i++){
            for(int j=0;j<BOARD_SIZE;j++){
                board[i][j] = "十";
            }
        }
    }
    //控制台输出棋盘
    public void printBoard(){
        for(int i=0;i<BOARD_SIZE;i++){
            for(int j=0;j<BOARD_SIZE;j++){
                System.out.print(board[i][j]);
            }
            System.out.print("\n");
        }
    }
    public boolean judge(int y,int x,String s) {
      int left  = (x-4>=0)?(x-4):0;
      int right = (x+4<BOARD_SIZE)?x+4:BOARD_SIZE;
      int up    = (y-4>=0)?(y-4):0;
      int down  = (y+4<BOARD_SIZE)?y+4:BOARD_SIZE;
      int tmpx = x;
      int tmpy = y;
      int zx = x;
      int zx2 = x;
      int zy = y;
      int zy2 = y;
      while(s.equals(board[y][tmpx])&&tmpx>left) {
        tmpx--;
      }
      while(s.equals(board[tmpy][x])&&tmpy>up){
        tmpy--;
      }
      while(s.equals(board[zy][zx])&&zx>left&&zy>up) {//左上
        zy--;
        zx--;
      }
      while(s.equals(board[zy2][zx2])&&zx>left&&zy<down) {//左下
        zy2++;
        zx2--;
      }
      int countx=0;
      int county=0;
      int countz1 = 0;
      int countz2 = 0;
      //x轴y轴判断
      for(int i=tmpx;i<=right;i++) {
        if(s.equals(board[y][i])) {
          countx++;
        }
      }
      for(int j=tmpy;j<=down ;j++) {
        if(s.equals(board[j][x])) {
          county++;
        }
      }   
      //斜线判断
      for(int j=zy,i=zx;j<=down&&i<=right;j++,i++) {
        if(s.equals(board[j][i])) {
          countz1++;
        }
      }
      for(int j=zy2,i=zx2;j>=up&&i<=right;j--,i++) {
        if(s.equals(board[j][i])) {
          countz2++;
        }
      }
      
      if(countx>=5||county>=5||countz1>=5||countz2>=5) {
        return true;
      }
      
      return false;
    }
    
    public static void main(String[] args) throws Exception{
        Gobang gb = new Gobang();
        gb.initBoard();
        gb.printBoard();
        //获取键盘输入
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String inputStr = null;
        System.out.println("请输入下棋的坐标: x,y");
        boolean meWin = false;
        boolean youWin = false;
        boolean myTurn = true;
        while(( inputStr=br.readLine())!=null ){
            String[] posStrArr = inputStr.split(",");
            int xPos = Integer.parseInt(posStrArr[0]);
            int yPos = Integer.parseInt(posStrArr[1]);
            if(myTurn) {
                gb.board[yPos-1][xPos-1] = "●";
                meWin = gb.judge(yPos-1,xPos-1,"●");
            }
            else {
               gb.board[yPos-1][xPos-1] = "○";
               youWin = gb.judge(yPos-1,xPos-1,"○");
            }
            gb.printBoard();
            if(meWin) {
              System.out.println("meWin!");
              break;
            }else if(youWin) {
              System.out.println("youWin!");
              break;
            }
            myTurn = !myTurn;
            System.out.println("请输入下棋的坐标: x,y");
        }

    }

}


相关文章
|
4天前
|
消息中间件 存储 Java
使用Java构建实时数据处理流程
使用Java构建实时数据处理流程
|
7天前
|
NoSQL Java Redis
软件开发常见流程之宝塔初始化安装环境配置,Lam前面不选,直接跳商城,在宝塔内点击软件商城,安Mysql5.7,安java项目管理器,安Ngnix最新版,安Redis
软件开发常见流程之宝塔初始化安装环境配置,Lam前面不选,直接跳商城,在宝塔内点击软件商城,安Mysql5.7,安java项目管理器,安Ngnix最新版,安Redis
|
11天前
|
存储 Java 容器
Java数组的初始化方法
Java数组的初始化方法
|
10天前
|
存储 Java 索引
Java数组操作:基础与进阶指南
Java数组操作:基础与进阶指南
|
2天前
|
Java 数据格式
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
11 0
|
2天前
|
存储 安全 Java
Java面试题:如何在Java应用中实现有效的内存优化?在多线程环境下,如何确保数据的线程安全?如何设计并实现一个基于ExecutorService的任务处理流程?
Java面试题:如何在Java应用中实现有效的内存优化?在多线程环境下,如何确保数据的线程安全?如何设计并实现一个基于ExecutorService的任务处理流程?
8 0
|
3天前
|
Java Apache Maven
Java:commons-codec实现byte数组和16进制字符串转换
在上述代码中,`Hex.encodeHexString(bytes)`用于将byte数组转换为16进制字符串,`Hex.decodeHex(hexString)`用于将16进制字符串转换为byte数组。
7 0
|
4天前
|
Java Apache Maven
Java:commons-codec实现byte数组和16进制字符串转换
在上述代码中,`Hex.encodeHexString(bytes)`用于将byte数组转换为16进制字符串,`Hex.decodeHex(hexString)`用于将16进制字符串转换为byte数组。
13 0
|
11天前
|
Java 索引
解决Java中的数组越界异常的技术
解决Java中的数组越界异常的技术
|
11天前
|
Java
【Java】程序练习1(数组)
【Java】程序练习1(数组)