背景
本文是《Java 后端从小白到大神》修仙系列第三篇,正式进入Java后端世界,本篇文章主要聊Java基础中的运算符、流程控制语句和数学相关内容。若若想详细学习请点击首篇博文,我们开始吧。
章节概览
- 运算符
- 流程控制语句
- 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
|
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引入的特性,使用 0b 或 0B 前缀表示二进制数。
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编程的核心基础知识,需要熟练掌握。
-
运算符:
- 算术运算符:用于基本数学运算
- 关系运算符:用于比较值的关系
- 逻辑运算符:用于连接布尔表达式
- 赋值运算符:用于给变量赋值
- 三目运算符:用于简洁的条件判断
- 运算符优先级:决定表达式的执行顺序
-
流程控制语句:
- 条件控制:if-else和switch语句
- 循环控制:for、while和do-while循环
- 跳转控制:break和continue语句
- 流程控制最佳实践:循环优化、嵌套控制、现代语法优先和防御式编程
-
Java数学相关内容:
- 二进制字面量:使用0b/0B前缀表示二进制数
- 位运算:直接操作二进制位,效率高
- 进制转换:在不同进制之间进行转换
- 数值处理陷阱:浮点数精度、整数溢出等问题
通过扎实掌握本文介绍的基础知识,你将为后续的Java学习和开发打下坚实的基础。记住,编程是一门实践的艺术,不断练习和积累经验是提高编程技能的关键。