背景

本文是《Java 后端从小白到大神》修仙系列第三篇,正式进入Java后端世界,本篇文章主要聊Java基础中的运算符、流程控制语句和数学相关内容。若若想详细学习请点击首篇博文,我们开始吧。

章节概览

  1. 运算符
  2. 流程控制语句
  3. Java 数学相关内容

1. 运算符

1. 算术运算符

算术运算符用于执行基本的数学运算,是Java编程中最常用的运算符之一。

运算符 描述 示例 结果(假设a=10,b=3)
+ 加法 a + b 13
- 减法 a - b 7
* 乘法 a * b 30
/ 除法 a / b 3(整数除法)
% 取模 a % b 1
++ 自增 a++(后缀)或 ++a 11(前缀先增,后缀后增)
-- 自减 b--(后缀)或 --b 2(前缀先减,后缀后减)

代码示例

1
2
3
4
5
6
7
8
int a = 10;
int b = 3;
System.out.println(a / b); // 输出 3(整数除法)
System.out.println((double)a / b); // 输出 3.333...

int x = 5;
int y = x++; // y=5, x=6(后缀自增)
int z = ++x; // x=7, z=7(前缀自增)

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 计算商品折扣
double originalPrice = 199.99;
double discountRate = 0.8; // 8折
double discountedPrice = originalPrice * discountRate;
System.out.println("折扣后价格: " + discountedPrice);

// 计算平均值
int[] scores = {85, 92, 78, 90, 88};
int sum = 0;
for (int score : scores) {
    sum += score;
}
double average = (double) sum / scores.length;
System.out.println("平均分数: " + average);

注意事项

  • 整数除法会自动舍去小数部分,如需精确计算请使用浮点数
  • 自增自减运算符在表达式中使用时,前缀和后缀的行为不同
  • 避免在复杂表达式中过度使用自增自减运算符,以免降低代码可读性

2. 关系运算符

关系运算符用于比较两个值的关系,返回布尔类型的结果(true或false)。

运算符 描述 示例 结果(假设a=5,b=10)
== 等于 a == b false
!= 不等于 a != b true
> 大于 a > b false
< 小于 a < b true
>= 大于等于 a >= 5 true
<= 小于等于 b <= 10 true

代码示例

1
2
3
4
5
6
7
8
9
int age = 18;
boolean isAdult = age >= 18; // true
boolean isTeenager = age >= 13 && age < 18; // false

// 比较对象引用(不推荐)
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(比较内存地址)
System.out.println(s1.equals(s2)); // true(比较内容)

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 验证用户输入
int score = getUserInput();
if (score >= 0 && score <= 100) {
    System.out.println("输入有效");
} else {
    System.out.println("输入无效,请输入0-100之间的分数");
}

// 比较对象
User user1 = new User("张三");
User user2 = new User("张三");
if (user1.equals(user2)) {
    System.out.println("用户相同");
} else {
    System.out.println("用户不同");
}

注意事项

  • 不可用于直接比较对象引用(比较对象内容用 equals(),比较内存地址用 ==
  • 对于包装类型(如Integer),应使用 equals() 进行比较,避免自动装箱/拆箱的性能问题
  • 浮点数比较应避免使用 ==,因为浮点数存在精度问题

3. 逻辑运算符

逻辑运算符用于连接布尔表达式,返回布尔类型的结果。

运算符 描述 示例 结果(假设A=true,B=false)
&& 短路与 A && B false
|| 短路或 A||B true
! !B true
& 非短路与 A & B false
| 非短路或 A|B true
^ 异或 A ^ B true(不同则为真)

短路特性

1
2
3
4
5
// && 示例:如果第一个条件为 false,不执行第二个判断
if (obj != null && obj.getValue() > 0) { ... }

// || 示例:如果第一个条件为 true,不执行第二个判断
if (x < 0 || x > 100) { ... }

代码示例

1
2
3
4
5
6
7
8
9
boolean hasPermission = true;
boolean isLoggedIn = true;
boolean canAccess = hasPermission && isLoggedIn; // true

boolean isAdmin = false;
boolean canEdit = isAdmin || hasPermission; // true

boolean isActive = true;
boolean isInactive = !isActive; // false

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 权限检查
if (user != null && user.isLoggedIn() && user.hasPermission("admin")) {
    System.out.println("管理员权限验证通过");
} else {
    System.out.println("权限不足");
}

// 输入验证
if (username == null || username.isEmpty() || username.length() < 3) {
    System.out.println("用户名无效");
} else {
    System.out.println("用户名有效");
}

短路与非短路的区别

  • &&(短路与):如果第一个条件为false,不执行第二个条件
  • &(非短路与):无论第一个条件结果如何,都会执行第二个条件
  • ||(短路或):如果第一个条件为true,不执行第二个条件
  • |(非短路或):无论第一个条件结果如何,都会执行第二个条件

使用建议

  • 一般情况下优先使用短路运算符(&&、||),可以提高性能
  • 当需要确保两个条件都执行时(如需要执行副作用操作),使用非短路运算符

4. 赋值运算符

赋值运算符用于给变量赋值,其中复合赋值运算符可以简化代码并自动进行类型转换。

运算符 描述 示例 等价于
= 基本赋值 a = 5 -
+= 加后赋值 a += 3 a = a + 3
-= 减后赋值 b -= 2 b = b - 2
*= 乘后赋值 c *= 4 c = c * 4
/= 除后赋值 d /= 2 d = d / 2
%= 取模赋值 e %= 3 e = e % 3
<<= 左移位赋值运算符 c <<= 2 c = c << 2
>>= 右移位赋值运算符 c >>= 2 c = c >> 2
&= 按位与赋值运算符 c &= 2 c = c & 2
^= 按位异或赋值操作符 c ^= 2 c = c ^ 2
|= 按位或赋值操作符 c |= 2 c = c | 2

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int a = 10;
a += 5; // 等价于 a = a + 5,结果为 15

int b = 20;
b -= 3; // 等价于 b = b - 3,结果为 17

int c = 5;
c *= 4; // 等价于 c = c * 4,结果为 20

// 类型转换示例
int num = 5;
num += 3.14; // 合法,等价于 num = (int)(num + 3.14),结果为 8

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 累计计算
int total = 0;
for (int i = 1; i <= 100; i++) {
    total += i; // 累加 1 到 100
}
System.out.println("1到100的和: " + total);

// 字符串拼接
String message = "Hello";
message += " World";
message += "!";
System.out.println(message); // 输出 "Hello World!"

// 位运算应用
int flags = 0;
flags |= 1; // 设置第0位为1
flags |= 4; // 设置第2位为1
System.out.println("Flags: " + flags); // 输出 5 (二进制 101)

注意事项

  • 复合赋值运算符会自动进行类型转换,这是与普通赋值运算符的重要区别
  • 对于字符串,+= 运算符用于字符串拼接
  • 对于对象引用,= 运算符只是复制引用,而不是创建新对象

5. 三目运算符(条件运算符)

三目运算符是Java中唯一的三元运算符,用于根据条件选择不同的表达式执行。

运算符 描述 格式 示例
?: 条件运算 条件 ? 表达式1 : 表达式2 int max = (a > b) ? a : b;

代码示例

1
2
3
4
5
6
7
int score = 85;
String result = (score >= 60) ? "及格" : "不及格";
System.out.println(result); // 输出 "及格"

// 嵌套使用
int x = 10, y = 20, z = 15;
int max = (x > y) ? (x > z ? x : z) : (y > z ? y : z); // 输出 20

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 计算折扣
double price = 199.99;
double discount = (price > 100) ? 0.8 : 1.0;
double finalPrice = price * discount;
System.out.println("最终价格: " + finalPrice);

// 格式化输出
int age = 25;
String ageGroup = (age < 18) ? "青少年" : (age < 60) ? "成年人" : "老年人";
System.out.println("年龄组: " + ageGroup);

// 空值处理
String name = user != null ? user.getName() : "未知用户";
System.out.println("用户名: " + name);

使用建议

  • 适用于简单的条件判断,使代码更简洁
  • 避免过度嵌套,嵌套层级不宜超过2层
  • 对于复杂的条件逻辑,建议使用if-else语句提高可读性

与if-else的对比

特性 三目运算符 if-else语句
语法 表达式形式,可直接赋值 语句块形式
可读性 简单条件时更简洁 复杂条件时更清晰
适用场景 简单的二选一操作 复杂的多条件分支

6. 运算符优先级

运算符优先级决定了表达式中运算的执行顺序,了解优先级可以避免因运算顺序错误导致的 bug。

以下为常见运算符优先级(从高到低):

  1. () 括号
  2. ++ --(后缀/前缀)
  3. * / %
  4. + -
  5. > < >= <= == !=
  6. && ||
  7. ?:
  8. = += -= 等赋值运算符

代码示例

1
2
3
4
5
6
int a = 10, b = 5, c = 3;
int result1 = a + b * c; // 先乘后加,结果为 25
int result2 = (a + b) * c; // 先加后乘,结果为 45

boolean flag = false && true || true; // 先与后或,结果为 true
boolean flag2 = false && (true || true); // 先或后与,结果为 false

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 计算表达式
double price = 199.99;
int quantity = 5;
double discount = 0.8;
double total = price * quantity * discount; // 正确的计算顺序

// 条件判断
int age = 25;
boolan isAdult = age >= 18 && age < 60; // 正确的逻辑运算顺序

// 复杂表达式
int result = (a + b) * (c - d) / e; // 使用括号明确优先级

建议

  • 复杂表达式使用括号明确优先级,提高代码可读性
  • 避免过度依赖运算符优先级,使用括号使逻辑更清晰
  • 对于复杂的表达式,考虑拆分为多个简单表达式

2. 流程控制语句

流程控制语句用于控制程序的执行流程,是Java编程中实现复杂逻辑的基础。

1. 条件控制

1. if-else

if-else语句是最基本的条件控制结构,用于根据条件执行不同的代码块。

if-else 流程

开始
  ↓
[条件判断] → true → 执行代码块 → 结束
  ↓ false
[else if 判断] → true → 执行代码块 → 结束
  ↓ false
[else 代码块] → 结束
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 基础结构
int score = 85;
if (score >= 90) {
    System.out.println("优秀");
} else if (score >= 80) {
    System.out.println("良好"); // 输出此行
} else {
    System.out.println("继续努力");
}

// 嵌套结构(避免超过3层)
if (user != null) {
    if (user.isVIP()) {
        // VIP处理逻辑
    } else {
        // 普通用户处理
    }
}

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 用户登录验证
if (username != null && password != null) {
    if (authenticate(username, password)) {
        System.out.println("登录成功");
        if (user.isFirstLogin()) {
            System.out.println("欢迎首次登录");
        }
    } else {
        System.out.println("用户名或密码错误");
    }
} else {
    System.out.println("请输入用户名和密码");
}

// 订单处理
if (order != null) {
    if (order.getStatus() == OrderStatus.PENDING) {
        processPendingOrder(order);
    } else if (order.getStatus() == OrderStatus.SHIPPED) {
        processShippedOrder(order);
    } else {
        System.out.println("未知订单状态");
    }
}

最佳实践

  • 始终使用 {} 包裹代码块(即使只有一行代码)
  • 复杂条件判断优先考虑策略模式替代多层嵌套
  • 避免深度嵌套(一般不超过3层)
  • 对于多个条件的判断,考虑使用switch语句或策略模式

2. switch(Java 12+ 增强版)

switch语句用于处理多个固定值的条件判断,Java 12+引入了增强版switch表达式,使代码更简洁。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 传统语法(需要break)
String day = "MON";
switch (day) {
    case "MON":
    case "TUE":
        System.out.println("工作日");
        break;
    case "SAT":
    case "SUN":
        System.out.println("周末");
        break;
    default:
        System.out.println("非法输入");
}

// 现代语法(箭头表达式 + yield)
String result = switch (day) {
    case "MON", "TUE" -> "工作日";
    case "SAT", "SUN" -> {
        System.out.println("检测到周末");
        yield "周末"; // 代码块中使用yield返回值
    }
    default -> throw new IllegalArgumentException();
};

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 处理HTTP状态码
int statusCode = 200;
String statusMessage = switch (statusCode) {
    case 200 -> "OK";
    case 404 -> "Not Found";
    case 500 -> "Internal Server Error";
    default -> "Unknown Status";
};
System.out.println("Status: " + statusMessage);

// 计算季节
int month = 3;
String season = switch (month) {
    case 12, 1, 2 -> "冬季";
    case 3, 4, 5 -> "春季";
    case 6, 7, 8 -> "夏季";
    case 9, 10, 11 -> "秋季";
    default -> "无效月份";
};
System.out.println("当前季节: " + season);

版本对比

特性 传统switch 增强switch(Java12+)
语法 case: + break case -> 表达式
返回值 不支持 支持通过yield返回值
多值匹配 需要多个case case "A", "B" ->
穿透风险 存在(需手动break)
代码简洁度 较冗长 更简洁
可读性 一般 更好

2. 循环控制

循环控制语句用于重复执行代码块,是处理重复任务的重要工具。

1. for循环

for循环是最常用的循环结构,适用于已知循环次数的场景。

for 循环流程

初始化 → 条件检查 → true → 执行循环体 → 更新表达式
                   ↓ false
                   结束
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 基础for循环
for (int i = 0; i < 10; i++) {
    System.out.print(i + " "); // 0-9
}

// 增强for循环(遍历数组/集合)
int[] nums = {1, 2, 3};
for (int num : nums) {
    System.out.print(num + " "); // 1 2 3
}

// 无限循环(慎用)
for (;;) {
    // 需要明确的退出条件
    if (condition) break;
}

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 遍历数组
int[] scores = {85, 92, 78, 90, 88};
double sum = 0;
for (int score : scores) {
    sum += score;
}
double average = sum / scores.length;
System.out.println("平均分数: " + average);

// 生成乘法表
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        System.out.print(j + "×" + i + "=" + (i*j) + "\t");
    }
    System.out.println();
}

// 处理集合
List<String> names = Arrays.asList("张三", "李四", "王五");
for (String name : names) {
    System.out.println("Hello, " + name);
}

2. while循环

while循环适用于未知循环次数,只知道循环条件的场景。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 先判断后执行
int count = 0;
while (count < 5) {
    System.out.print(count + " "); // 0-4
    count++;
}

// 无限循环标准写法
while (true) {
    // 必须包含break条件
    if (shouldExit) break;
}

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 猜数字游戏
Scanner scanner = new Scanner(System.in);
int target = (int)(Math.random() * 100) + 1;
int guess = 0;
while (guess != target) {
    System.out.print("请输入一个1-100之间的数字: ");
    guess = scanner.nextInt();
    if (guess < target) {
        System.out.println("太小了");
    } else if (guess > target) {
        System.out.println("太大了");
    } else {
        System.out.println("恭喜你猜对了!");
    }
}

// 读取文件
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
String line;
while ((line = reader.readLine()) != null) {
    System.out.println(line);
}
reader.close();

3. do-while循环

do-while循环适用于至少需要执行一次的场景,先执行后判断。

1
2
3
4
5
6
// 先执行后判断(至少执行一次)
int x = 5;
do {
    System.out.print(x + " "); // 输出5
    x++;
} while (x < 3);

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 菜单选择
Scanner scanner = new Scanner(System.in);
int choice;
do {
    System.out.println("1. 查看余额");
    System.out.println("2. 存款");
    System.out.println("3. 取款");
    System.out.println("4. 退出");
    System.out.print("请选择操作: ");
    choice = scanner.nextInt();
    
    switch (choice) {
        case 1:
            System.out.println("余额查询");
            break;
        case 2:
            System.out.println("存款操作");
            break;
        case 3:
            System.out.println("取款操作");
            break;
        case 4:
            System.out.println("退出系统");
            break;
        default:
            System.out.println("无效选择");
    }
} while (choice != 4);

// 输入验证
do {
    System.out.print("请输入正数: ");
    num = scanner.nextInt();
} while (num <= 0);

3. 跳转控制

跳转控制语句用于控制循环的执行流程,包括break和continue语句。

1. break

break语句用于跳出当前循环或switch语句,终止循环的执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 基础用法(跳出当前循环)
for (int i = 0; i < 10; i++) {
    if (i == 5) break;
    System.out.print(i + " "); // 0-4
}

// 带标签的break(跳出多层循环)
outerLoop: 
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 1) break outerLoop;
        System.out.println(i + "-" + j);
    }
}
// 输出:
// 0-0
// 0-1
// 0-2
// 1-0

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 查找元素
int[] numbers = {1, 3, 5, 7, 9};
int target = 5;
int index = -1;
for (int i = 0; i < numbers.length; i++) {
    if (numbers[i] == target) {
        index = i;
        break; // 找到目标后跳出循环
    }
}
System.out.println("元素" + target + "在索引" + index + "位置");

// 多层循环跳出
outer: 
for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 100; j++) {
        if (i * j > 500) {
            System.out.println("找到满足条件的i=" + i + ", j=" + j);
            break outer; // 跳出所有循环
        }
    }
}

2. continue

continue语句用于跳过当前迭代,继续下一次循环。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 跳过当前迭代
for (int i = 0; i < 5; i++) {
    if (i % 2 == 0) continue;
    System.out.print(i + " "); // 1 3
}

// 带标签的continue
outer: 
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (j == 1) continue outer;
        System.out.println(i + "-" + j);
    }
}
// 输出:
// 0-0
// 1-0
// 2-0

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 过滤元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = new ArrayList<>();
for (int num : numbers) {
    if (num % 2 != 0) continue; // 跳过奇数
    evenNumbers.add(num);
}
System.out.println("偶数列表: " + evenNumbers);

// 跳过异常情况
for (String url : urls) {
    try {
        fetchData(url);
    } catch (Exception e) {
        System.err.println("处理" + url + "时出错: " + e.getMessage());
        continue; // 跳过出错的URL,继续处理下一个
    }
}

// 带标签的continue应用
outer: 
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= 9; j++) {
        if (j > i) continue outer; // 跳过j > i的情况,生成上三角乘法表
        System.out.print(j + "×" + i + "=" + (i*j) + "\t");
    }
    System.out.println();
}

4. 流程控制最佳实践

良好的流程控制实践可以提高代码的可读性、性能和可维护性。

1. 循环优化

循环优化可以显著提升程序性能,特别是在处理大量数据时。

优化技巧

  • 避免在循环内创建对象(如 new ArrayList()
  • 复杂条件判断提到循环外部
  • 减少循环内的方法调用
  • 优先使用增强for循环遍历数组和集合
  • 合理使用循环展开(对于固定次数的循环)

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 优化前:在循环内创建对象
for (int i = 0; i < 1000; i++) {
    List<Integer> list = new ArrayList<>(); // 每次循环都创建新对象
    list.add(i);
}

// 优化后:在循环外创建对象
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
    list.add(i);
}

// 优化前:复杂条件判断在循环内
for (int i = 0; i < array.length; i++) {
    if (condition1() && condition2() && condition3()) {
        // 处理逻辑
    }
}

// 优化后:复杂条件判断在循环外
boolean conditions = condition1() && condition2() && condition3();
for (int i = 0; i < array.length; i++) {
    if (conditions) {
        // 处理逻辑
    }
}

2. 嵌套控制

过多的嵌套会降低代码可读性,增加维护难度。

最佳实践

  • 循环嵌套不超过3层(否则应考虑重构)
  • 优先使用 break 替代循环控制变量
  • 考虑将复杂的嵌套逻辑提取为方法
  • 使用提前返回(early return)减少嵌套

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 优化前:深层嵌套
if (user != null) {
    if (user.isActive()) {
        if (user.hasPermission("admin")) {
            if (action != null) {
                // 处理逻辑
            }
        }
    }
}

// 优化后:提前返回减少嵌套
if (user == null || !user.isActive() || !user.hasPermission("admin") || action == null) {
    return;
}
// 处理逻辑

// 优化前:使用循环控制变量
boolean found = false;
for (int i = 0; i < array.length && !found; i++) {
    if (array[i] == target) {
        found = true;
        // 处理逻辑
    }
}

// 优化后:使用break
for (int i = 0; i < array.length; i++) {
    if (array[i] == target) {
        // 处理逻辑
        break;
    }
}

3. 现代语法优先

Java 8+引入了许多现代语法特性,可以使代码更简洁、更易读。

推荐使用

  • 增强switch表达式(Java 12+)
  • 流式API(Stream API)
  • 方法引用
  • Lambda表达式
  • 可选类型(Optional)

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 使用增强switch替代传统写法
String type = switch (code) {
    case 200 -> "成功";
    case 404 -> "未找到";
    default -> "未知状态";
};

// 使用流式API替代传统循环
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());

// 使用方法引用
List<String> names = Arrays.asList("张三", "李四", "王五");
names.forEach(System.out::println);

4. 防御式编程

防御式编程可以提高代码的健壮性,减少运行时错误。

核心原则

  • 循环必须有安全退出机制
  • 对用户输入进行验证
  • 处理可能的异常情况
  • 避免空指针异常
  • 合理使用断言

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 循环必须有安全退出机制
int retry = 0;
final int MAX_RETRY = 5;
while (retry < MAX_RETRY) {
    if (operation()) {
        break;
    }
    retry++;
    try {
        Thread.sleep(1000); // 避免无限快速重试
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        break;
    }
}

// 防御式编程示例
public void processUserInput(String input) {
    // 验证输入
    if (input == null || input.trim().isEmpty()) {
        throw new IllegalArgumentException("输入不能为空");
    }
    
    // 处理可能的异常
    try {
        // 处理逻辑
    } catch (Exception e) {
        logger.error("处理输入时出错: " + e.getMessage(), e);
        // 适当的错误处理
    }
}

3. Java 数学相关内容

Java 提供了丰富的数学相关功能,包括二进制字面量、位运算和进制转换等,这些功能在底层编程和性能优化中非常重要。

1. 二进制字面量

二进制字面量是Java 7引入的特性,使用 0b0B 前缀表示二进制数。

1
2
3
4
5
int binaryNum = 0b1010; // 二进制前缀 0b/0B
System.out.println(binaryNum); // 输出十进制 10

// 二进制字面量的应用
int flag = 0b1010; // 表示第1位和第3位为1(从0开始计数)

实际应用场景

  • 表示位标志(如权限控制)
  • 直接操作二进制数据
  • 硬件相关编程

2. 位运算

位运算是直接对整数的二进制位进行操作的运算,效率非常高,常用于底层编程和性能优化。

运算符 描述 示例(a=60=0b0011 1100, b=13=0b0000 1101) 结果(二进制)
& 按位与(对应的两个二进制位均为1时,结果才为1) a & b 得到12,即0000 1100
| 按位或(对应的两个二进制位有一个为1,结果就为1) a | b 得到61,即 0011 1101
^ 按位异或(如果相对应位值相同,则结果为0,否则为1) a ^ b 得到49,即 0011 0001
~ 按位非(如果位为0,结果是1,如果位为1,结果是0) ~a 得到-61,即1100 0011
<< 左移(按位左移运算符,左操作数按位左移右操作数指定的位数) a << 2 得到240,即 1111 0000
>> 带符号右移(按位右移运算符,左操作数按位右移右操作数指定的位数) a >> 1 得到15即 1111
>>> 无符号右移(按位右移补零操作符,左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充) a >>> 1 得到15即0000 1111

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 按位与:提取特定位
int flags = 0b101010;
int mask = 0b100000;
boolean hasFlag = (flags & mask) != 0; // 检查第5位是否为1

// 按位或:设置特定位
int newFlags = flags | 0b010000; // 设置第4位为1

// 按位异或:切换特定位
int toggledFlags = flags ^ 0b100000; // 切换第5位

// 左移:乘以2的幂
int result = 5 << 2; // 5 * 2^2 = 20

// 右移:除以2的幂
int result2 = 20 >> 2; // 20 / 2^2 = 5

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 权限管理(位标志)
public class Permission {
    public static final int READ = 1 << 0;   // 0b0001
    public static final int WRITE = 1 << 1;  // 0b0010
    public static final int EXECUTE = 1 << 2; // 0b0100
    public static final int DELETE = 1 << 3;  // 0b1000
    
    public static boolean hasPermission(int permissions, int permission) {
        return (permissions & permission) != 0;
    }
    
    public static int addPermission(int permissions, int permission) {
        return permissions | permission;
    }
    
    public static int removePermission(int permissions, int permission) {
        return permissions & ~permission;
    }
}

// 位运算优化
// 计算2的幂
int powerOfTwo = 1 << n; // 等价于 Math.pow(2, n),但更高效

// 检查是否为2的幂
boolean isPowerOfTwo = (n & (n - 1)) == 0 && n > 0;

// 取模运算(当除数是2的幂时)
int modResult = value & (divisor - 1); // 等价于 value % divisor

3. 进制转换

Java 提供了多种进制转换方法,方便在不同进制之间进行转换。

1. 二进制转其他进制

1
2
3
4
Integer.toOctalString(0b1011); // 二进制转八进制输出
Integer.toHexString(0b1011); // 二进制转十六进制输出
Integer.toBinaryString(11); // 十进制转二进制输出
Integer.toHexString(11); // 十进制转十六进制输出

2. 其他进制转二进制

1
2
3
Integer.toBinaryString(013);// 八进制转二进制输出
Integer.toBinaryString(11);// 十进制转二进制输出
Integer.toBinaryString(0xb);// 十六进制转二进制输出

3. 其他进制转十进制

1
2
3
4
5
6
7
8
System.out.println(013);// 八进制转十进制输出
System.out.println(0b1011);// 二进制转十进制输出
System.out.println(0xb);// 十六进制转十进制输出

// 使用Integer.parseInt进行进制转换
int decimal1 = Integer.parseInt("1011", 2); // 二进制转十进制
int decimal2 = Integer.parseInt("13", 8); // 八进制转十进制
int decimal3 = Integer.parseInt("B", 16); // 十六进制转十进制

4. 其他进制转八进制

1
2
3
Integer.toOctalString(0b1011);// 二进制转八进制输出
Integer.toOctalString(11);// 十进制转八进制输出
Integer.toOctalString(0xb);// 十六进制转八进制输出

5. 其他进制转十六进制

1
2
3
Integer.toHexString(013);// 八进制转十六进制输出
Integer.toHexString(11);// 十进制转十六进制输出
Integer.toHexString(0b1011);// 二进制转十六进制输出

实际应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 网络编程中的IP地址转换
String ip = "192.168.1.1";
String[] parts = ip.split("\\.");
int ipInt = 0;
for (String part : parts) {
    ipInt = (ipInt << 8) | Integer.parseInt(part);
}
System.out.println("IP地址的整数表示: " + ipInt);
System.out.println("IP地址的十六进制表示: " + Integer.toHexString(ipInt));

// 颜色值处理
int color = 0xFFAABB; // 十六进制颜色值
int red = (color >> 16) & 0xFF;
int green = (color >> 8) & 0xFF;
int blue = color & 0xFF;
System.out.println("Red: " + red + ", Green: " + green + ", Blue: " + blue);

6. 数值处理陷阱

在进行数值处理时,需要注意以下常见陷阱:

  • 浮点数精度问题:避免用 == 比较 double,应使用 Math.abs(a - b) < epsilon
  • 整数溢出:如 Integer.MAX_VALUE + 1 变负数,应使用 Math.addExact() 或检查溢出
  • 位移运算优先级a << 2 + 1 实际是 a << (2+1),应使用括号明确优先级
  • 除以零:整数除以零会抛出异常,浮点数除以零会得到 Infinity
  • 负数的位运算:负数在Java中使用补码表示,位运算时需要注意符号位

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 浮点数比较
double a = 0.1 + 0.2;
double b = 0.3;
// 错误的比较方式
if (a == b) { // 可能为false,因为浮点数精度问题
    System.out.println("相等");
}
// 正确的比较方式
if (Math.abs(a - b) < 1e-10) {
    System.out.println("相等");
}

// 避免整数溢出
int max = Integer.MAX_VALUE;
try {
    int result = Math.addExact(max, 1);
} catch (ArithmeticException e) {
    System.out.println("发生整数溢出");
}

// 正确的位移运算
int a = 5;
int result1 = a << (2 + 1); // 正确:先计算括号内的表达式
int result2 = (a << 2) + 1; // 正确:明确优先级

总结

本文详细介绍了Java基础中的运算符、流程控制语句和数学相关内容,这些是Java编程的核心基础知识,需要熟练掌握。

  1. 运算符

    • 算术运算符:用于基本数学运算
    • 关系运算符:用于比较值的关系
    • 逻辑运算符:用于连接布尔表达式
    • 赋值运算符:用于给变量赋值
    • 三目运算符:用于简洁的条件判断
    • 运算符优先级:决定表达式的执行顺序
  2. 流程控制语句

    • 条件控制:if-else和switch语句
    • 循环控制:for、while和do-while循环
    • 跳转控制:break和continue语句
    • 流程控制最佳实践:循环优化、嵌套控制、现代语法优先和防御式编程
  3. Java数学相关内容

    • 二进制字面量:使用0b/0B前缀表示二进制数
    • 位运算:直接操作二进制位,效率高
    • 进制转换:在不同进制之间进行转换
    • 数值处理陷阱:浮点数精度、整数溢出等问题

通过扎实掌握本文介绍的基础知识,你将为后续的Java学习和开发打下坚实的基础。记住,编程是一门实践的艺术,不断练习和积累经验是提高编程技能的关键。