likes
comments
collection
share

Java之运算符与流程控制

作者站长头像
站长
· 阅读数 13

今天继续更新Java系列,接着来看下Java运算符和流程控制。

运算符

运算符是一种特殊的符号,用以表示数据的运算赋值和比较等。

运算符的分类:

# 按照功能分类如下:
# 算术运算符(7个):+、-、*、/、%、++、--
# 赋值运算符(12个):=、+=、-=、*=、/=、%=、>>=、<<=、>>>=、&=、|=、^=等
# 比较(或关系)运算符(6个):>、>=、<、<=、==、!=
# 逻辑运算符(6个):&、|、^、!、&&、||
# 位运算符(7个):&、|、^、~、<<、>>、>>>
# 条件运算符(1个):(条件表达式)?结果1:结果2
# Lambda运算符(1个):->(第18章时讲解)

算术运算符

Java之运算符与流程控制 举例:

int m = 2;
m = m++;
System.out.println(m);
//先取m的值2放操作数栈,m再自增1,此时m=3,最后把操作数栈中的2赋值给m,故输出m=2

赋值运算符

赋值运算符符号解释
+=将符号左边的值和右边的值进行相加操作,最后将结果赋值给左边的变量
-=将符号左边的值和右边的值进行相减操作,最后将结果赋值给左边的变量
*=将符号左边的值和右边的值进行相乘操作,最后将结果赋值给左边的变量
/=将符号左边的值和右边的值进行相除操作,最后将结果赋值给左边的变量
%=将符号左边的值和右边的值进行取余操作,最后将结果赋值给左边的变量

举例:

public class MinusTest {
    public static void main(String[] args) {
        //变量值减1
        short s = 10;
        //方法1
        //s = (short)(s - 1);
        //方法2,推荐
        s--; //或者用--s
        //方法3
        s -= 1;
        //变量值减2
        short s1 = 10;
        //方法1
        //s1 = (short)(s1 - 2);
        //方法2,推荐
        s1 -= 2;
    }
}

比较运算符

Java之运算符与流程控制 比较运算符的结果都是boolean类型,要么是true要么是false。

>,<,>=,<=只适用于基本数据类型(除boolean类型之外),= =和!=适用于基本数据类型和引用数据类型。

逻辑运算符

Java之运算符与流程控制 逻辑运算符操作的都是boolean类型的变量或常量,而且运算的结果也是boolean类型的值。

区分&和&&:

  • 相同点:如果符号左边是true,则二者都执行符号右边的操作
  • 不同点:对于&,如果符号左边是false则继续执行符号右边的操作。对于&&,如果符号左边是false则不再继续执行符号右边的操作
  • 建议:开发中推荐使用&&

区分|和||:

  • 相同点:如果符号左边是false,则二者都执行符号右边的操作
  • 不同点:对于|,如果符号左边是true则继续执行符号右边的操作。对于||,如果符号左边是true则不再继续执行符号右边的操作
  • 建议:开发中推荐使用||

举例:

boolean x = true;
boolean y = false;
short z = 42;
if ((z++ == 42) && (y = true)) {
    z++;
}
if ((x = false) || (++z == 45)) {
    z++;
}
System.out.println("z=" + z); //输出为z=46

位运算符

Java之运算符与流程控制 Java之运算符与流程控制 位运算符的运算过程都是基于二进制的补码运算。

这里补充下补码的知识: 首先计算机数据的存储是使用二进制补码形式存储,并且最高位是符号位,正数的最高位是0,负数的最高位是1。

正数和负数的原码、反码、补码:

  • 正数的补码与反码、原码一样,称为三码合一
  • 负数的补码与反码、原码不一样
    • 负数的原码:把十进制转为二进制,然后最高位设置为1
    • 负数的反码:在原码的基础上,最高位不变,其余位取反(0变1,1变0)
    • 负数的补码:反码加1

举例: 怎么高效的计算2*8的值:

2 << 3
8 << 1

交换两个int变量的值,或者String变量的值:

public class BitTest {
    public static void main(String[] args) {
        int m = 10;
        int n = 5;
        System.out.println("m = " + m + ", n = " + n);
	//方法1:容易理解适用于不同数据类型,但是需要额外定义变量
	//int temp = m;
	//m = n;
	//n = temp;
	//方法2:没有额外定义变量,但是可能超出int的范围,只能适用于数值类型
	//m = m + n; //15 = 10 + 5
	//n = m - n;//10 = 15 - 5
	//m = m - n;//5 = 15 - 10
	//方法3:没有额外定义变量,但是不易理解,只能适用于数值类型
	m = m ^ n; 
	n = m ^ n; //(m ^ n) ^ n
	m = m ^ n;
	System.out.println("m = " + m + ", n = " + n);
    }
}

条件运算符

格式:(条件表达式)? 表达式1:表达式2

条件表达式是boolean类型的结果,根据boolean的值选择表达式1或表达式2,如果运算后的结果赋给新的变量,要求表达式1和表达式2为同种或兼容的类型。 Java之运算符与流程控制 举例: 今天是周二,十天后是周几:

public class ConditionTest {
    public static void main(String[] args) {
        int week = 2;
        week += 10;
        week %= 7;
        System.out.println("今天是周2,10天以后是周" + (week == 0 ? "日" : week));
    }
}

运算符优先级

运算符有不同的优先级,所谓优先级就是在表达式运算中的运算符顺序。

如下,上一行中的运算符总是优先于下一行的:

# 1括号:`()`、`[]`、`{}`
# 2正负号:`+`、`-`
# 3单元运算符:`++`、`--`、`~`、`!`
# 4乘法、除法、求余:`*`、`/`、`%`
# 5加法、减法:`+`、`-`
# 6移位运算符:`<<`、`>>`、`>>>`
# 7关系运算符:`<`、`<=`、`>=`、`>`、`instanceof`
# 8等价运算符:`==`、`!=`
# 9按位与:`&`
# 10按位异或:`^`
# 11按位或:`|`
# 12条件与:`&&`
# 13条件或:`||`
# 14三元运算符:`? :`
# 15赋值运算符:`=`、`+=`、`-=`、`*=`、`/=`、`%=`
# 16位赋值运算符:`&=`、`|=`、`<<=`、`>>=`、`>>>=`

:不要过多的依赖运算的优先级来控制表达式的执行顺序,这样可读性太差,尽量使用()来控制表达式的执行顺序。不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成几步来完成。

流程控制

顺序结构

顺序结构就是程序从上到下逐行地执行,表达式语句都是顺序执行的,并且上一行对某个变量的修改对下一行会产生影响。 Java之运算符与流程控制

分支语句

if-else

格式:

if (条件表达式1) { //条件表达式必须是布尔表达式或布尔变量
  	语句块1;
} else if (条件表达式2) {
  	语句块2;
}
...
}else if (条件表达式n) {
 	语句块n;
} else {
  	语句块n+1;
}

执行流程: Java之运算符与流程控制 if...else嵌套:在if的语句块中或在else语句块中,又包含了另一个条件判断,这样就构成了嵌套结构。当语句块中只有一条执行语句时一对{}可以省略,但建议保留。

switch-case

格式:

switch(表达式){
    case 常量值1:
        语句块1;
        //break;
    case 常量值2:
        语句块2;
        //break; 
    // ...
   [default:
        语句块n+1;
        break;
   ]
}

执行流程: Java之运算符与流程控制

  • switch(表达式)中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举 (jdk 5.0),String (jdk 7.0)
  • case子句中的值必须是常量,不能是变量名或不确定的表达式值或范围
  • 同一个switch语句,所有case子句中的常量值互不相同
  • break语句用来在执行完一个case分支后使程序跳出switch语句块,如果没有break,程序会顺序执行到switch结尾
  • default子句是可选的,同时位置也是灵活的,当没有匹配的case时执行default语句

:在switch语句中,如果case的后面不写break,将出现穿透现象,也就是一旦匹配成功,不会在判断下一个case的值,直接向后运行,直到遇到break或者整个switch语句结束。

比较

结论:凡是使用switch-case的结构都可以转换为if-else结构,反之不成立。

经验:如果既可以使用switch-case,又可以使用if-else,建议使用switch-case,效率稍高。

循环语句

for循环

格式:

for (①初始化部分; ②循环条件部分; ④迭代部分){
         	③循环体部分;
}

执行流程: Java之运算符与流程控制

  • for(;;)中的两个;不能多也不能少
  • 初始化部分可以声明多个变量,但必须是同一个类型,用逗号分隔
  • 循环条件部分为boolean类型表达式,当值为false时,退出循环
  • 可以有多个变量更新,用逗号分隔

举例: 打印1-100之间所有是7的倍数的整数的个数及总和(体会设置计数器的思想):

public class ForTest2 {
    public static void main(String[] args) {
        int sum = 0; //记录总和
        int count = 0; //记录个数
        for (int i = 1; i < 100; i++) {
            if(i % 7 == 0){
                sum += i;
                count++;
            }
        }
        System.out.println("1-100之间所有是7的倍数的整数的和为:" + sum);
        System.out.println("1-100之间所有是7的倍数的整数的个数为:" + count);
    }
}

while循环

格式:

①初始化部分
while(②循环条件部分){
    ③循环体部分;
    ④迭代部分;
}

执行流程: Java之运算符与流程控制

  • while(循环条件)中循环条件必须是boolean类型
  • 注意不要忘记声明4迭代部分,否则循环将不能结束变成死循环
  • for循环和while循环可以相互转换,二者没有性能上的差别。实际开发中,根据具体结构的情况,选择哪个格式更合适
  • for循环与while循环的区别:初始化条件部分的作用域不同

举例: 从键盘输入整数,统计输入的正数、负数的个数,最后输入0结束:

import java.util.Scanner;

public class TestWhile {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int positive = 0; //记录正数的个数
        int negative = 0; //记录负数的个数
        int num = 1; //初始化为特殊值,使得第一次循环条件成立
        while(num != 0){
            System.out.print("请输入整数(0表示结束):");
            num = input.nextInt();
            if(num > 0){
                positive++;
            }else if(num < 0){
                negative++;
            }
        }
        System.out.println("正数个数:" + positive);
        System.out.println("负数个数:" + negative);
        input.close();
    }
}

do-while循环

格式:

①初始化部分;
do{
	③循环体部分
	④迭代部分
}while(②循环条件部分); 

执行流程: Java之运算符与流程控制

  • 结尾while(循环条件)中循环条件必须是boolean类型
  • do{}while();最后有一个分号
  • do-while结构的循环体语句是至少会执行一次,这个和for和while是不一样的
  • 循环的三个结构for、while、do-while三者是可以相互转换的

举例: 随机生成一个100以内的数,猜这个随机数是多少:

import java.util.Scanner;

public class DoWhileTest {
    public static void main(String[] args) {
        //随机生成一个100以内的整数
        int num = (int)(Math.random()* 100);
        //声明一个变量,用来存储猜的次数
        int count = 0;
        Scanner input = new Scanner(System.in);
        int guess; //提升作用域
        do{
            System.out.print("请输入100以内的整数:");
            guess = input.nextInt();
            //输入一次,就表示猜了一次
            count++;
            if(guess > num){
                System.out.println("大了");
            }else if(guess < num){
                System.out.println("小了");
            }
        }while(num != guess);
        System.out.println("一共猜了:" + count+"次");
        input.close();
    }
}

嵌套循环

嵌套循环是指一个循环结构A的循环体是另一个循环结构B,比如for循环里面还有一个for循环,就是嵌套循环。其中for ,while ,do-while均可以作为外层循环或内层循环。

设外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次。

技巧:从二维图形的角度看,外层循环控制行数,内层循环控制列数

经验:实际开发中,我们最多见到的嵌套循环是两层,一般不会出现超过三层的嵌套循环。如果将要出现,一定要停下来重新梳理业务逻辑,重新思考算法的实现,控制在三层以内,否则可读性会很差。

break和continue的使用

关键字适用范围在循环结构中使用的作用相同点
breakswitch-case循环结构一旦执行就结束当前循环结构此关键字的后面不能声明语句
continue循环结构一旦执行就结束当次循环结构此关键字的后面不能声明语句

此外,很多语言都有goto语句,goto语句可以随意将控制转移到程序中的任意一条语句上,然后执行它,但使程序容易出错,Java中的break和continue是不同于goto的。

最后,今天的内容就到这里,Java教程持续更新中,喜欢的话点个关注吧,下篇见!