Java 中 BigDecimal 类与 Lambda 和流的使用
在 Java 编程中,处理小数和集合数据是常见的需求。
BigDecimal
类为处理小数提供了可靠的解决方案,而 Lambda 表达式和流则为处理集合数据提供了强大而简洁的方式。
1. BigDecimal 类的使用
BigDecimal
类为 Java 开发者提供了一种可预测的方式来处理小数。
1.1 小数位数与舍入
在
BigDecimal
中,scale 指的是小数点右侧的数字位数。例如:
aNum = 23.45
bNum = 23.4
aNum scale = 2
bNum scale = 1
这里
bNum
的值为 23.4 而非 23.5,是向下舍入的结果。
1.2 基本数学运算
在使用
BigDecimal
进行数学计算时,需要使用该类提供的方法,而不是数学运算符。基本方法如下:
-
add
:加法
-
subtract
:减法
-
multiply
:乘法
-
divide
:除法
以下是一个简单的示例代码:
import java.math.BigDecimal;
public class App {
public static void main(String[] args) {
BigDecimal aNum = new BigDecimal("10");
BigDecimal bNum = new BigDecimal("6");
BigDecimal result;
result = aNum.add(bNum);
System.out.println("Adding: " + result);
result = aNum.subtract(bNum);
System.out.println("Subtracting: " + result);
result = aNum.multiply(bNum);
System.out.println("Multiplying: " + result);
}
}
运行该代码,输出结果为:
Adding: 16
Subtracting: 4
Multiplying: 60
1.3 除法运算与舍入模式
在进行除法运算时,小数位数可能会增加,甚至可能出现无限循环小数。例如,10 除以 6 的结果是 1.6666…,这是一个无限循环小数。如果不指定舍入模式,
BigDecimal
会抛出
ArithmeticException
异常。
为避免此问题,需要设置舍入模式,示例代码如下:
import java.math.BigDecimal;
import java.math.RoundingMode;
public class App {
public static void main(String[] args) {
BigDecimal aNum = new BigDecimal("10");
BigDecimal bNum = new BigDecimal("6");
BigDecimal result;
result = aNum.divide(bNum, RoundingMode.HALF_UP);
System.out.println("Adding: " + result);
result = aNum.divide(bNum, 2, RoundingMode.HALF_UP);
System.out.println("Subtracting: " + result);
result = aNum.divide(bNum, 2, RoundingMode.DOWN);
System.out.println("Multiplying: " + result);
}
}
运行该代码,输出结果为:
2
1.67
1.66
1.4 重要要点总结
- Scale 指的是小数点右侧的数字位数。
-
BigDecimal提供了多种不同的舍入模式。 - 在进行除法运算时,设置舍入模式非常重要,因为该操作可能会导致小数点右侧出现无限循环的值。
-
BigDecimal对象是不可变的。
1.5 练习
-
练习 1:利息计算器
编写一个利息计算器程序,根据输入的年利率、初始本金和投资年限,计算投资后的总金额。新的季度金额计算公式为:CurrentBalance * (1 + (QuarterlyInterestRate / 100))。 -
练习 2:汽车销售服务层
创建一个服务层,用于模拟汽车销售程序。该服务层需要实现一些业务逻辑,如根据 VIN 获取汽车、获取所有汽车、根据颜色过滤汽车、根据预算过滤汽车等。
2. Lambda 表达式与流的使用
流与 Lambda 表达式结合,使开发者能够以强大的方式处理集合中的数据。
2.1 聚合操作
聚合操作使用 Lambda 表达式对集合中的对象执行操作。例如:
- 打印
Address
对象集合中所有人的姓名。
- 返回来自俄亥俄州阿克伦市的所有人的
Address
对象。
- 按邮政编码对来自俄亥俄州阿克伦市的所有人的
Address
对象进行分组。
- 计算库存中服务器的平均使用年限。
2.2 管道与流
管道是一系列聚合操作的序列,流是从数据源通过管道传输项目的序列(不是数据结构)。管道包括数据源、零个或多个中间操作和一个终端操作。
- 数据源:最常见的是集合,也可以是数组、方法调用的返回值或某种 I/O 通道。
- 中间操作:如过滤操作,接受一个流并生成一个新的流。
- 终端操作:返回非流结果,如基本类型、集合或无结果。
以下是一个简单的 mermaid 流程图,展示了管道和流的关系:
graph LR
A[数据源] --> B[中间操作1]
B --> C[中间操作2]
C --> D[终端操作]
D --> E[结果]
2.3 流与迭代的比较
虽然一些聚合操作(如
forEach
)看起来像迭代器,但它们有根本的区别:
- 聚合操作处理的是流中的项目,而不是直接处理集合中的项目。
- 聚合操作支持 Lambda 表达式作为参数。
2.4 Lambda 表达式
在编程中,Lambda 表达式是匿名函数或方法。在 Java 中,Lambda 表达式是函数式接口的实现,函数式接口是只有一个抽象方法的接口,如
Runnable
或
Comparable
接口。
2.5 流方法的使用
以下是一些常见流方法的使用示例:
2.5.1 forEach() 方法
forEach()
方法是一个终端操作,用于对流中的每个对象执行代码。例如:
import java.util.ArrayList;
import java.util.List;
public class App {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add( new Person("Alfred", 17));
people.add( new Person("Henrey", 18));
people.add( new Person("George", 19));
people.add( new Person("Joe", 27));
people.add( new Person("Zelda", 7));
for (Person currentPerson : people) {
System.out.print(currentPerson.getName());
System.out.print(" - ");
System.out.println(currentPerson.getAge());
}
System.out.println("======");
people.stream()
.forEach((currentPerson) -> {
System.out.print(currentPerson.getName());
System.out.print(" - ");
System.out.println(currentPerson.getAge());
});
}
}
该代码使用
forEach()
方法打印
Person
对象列表中的每个人的姓名和年龄。
2.5.2 filter() 方法
filter()
方法用于过滤流,只包含满足条件的对象。例如,过滤出年龄大于等于 18 岁的人:
people.stream()
.filter((p) -> p.getAge() >= 18)
这里的 Lambda 表达式
(p) -> p.getAge() >= 18
是一个谓词,返回布尔值。
通过使用
BigDecimal
类、Lambda 表达式和流,我们可以更高效、更简洁地处理小数和集合数据,提高代码的可读性和可维护性。
2.6 结合过滤与遍历操作
我们可以将
filter()
方法和
forEach()
方法结合使用,对集合中的数据进行过滤后再进行遍历操作。以下是一个示例代码:
package com.tsg.lambdafun;
import java.util.ArrayList;
import java.util.List;
public class App {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add( new Person("Alfred", 17));
people.add( new Person("Henrey", 18));
people.add( new Person("George", 19));
people.add( new Person("Joe", 27));
people.add( new Person("Zelda", 7));
System.out.println("==> Age 18 or greater ==");
people.stream()
.filter((currentPerson) ->
currentPerson.getAge() >= 18)
.forEach((currentPerson) -> {
System.out.print(currentPerson.getName());
System.out.print(" - ");
System.out.println(currentPerson.getAge());
});
System.out.println("==> Names start with G ==");
people.stream()
.filter((currentPerson) ->
currentPerson.getName().startsWith("G"))
.forEach((currentPerson) -> {
System.out.print(currentPerson.getName());
System.out.print(" - ");
System.out.println(currentPerson.getAge());
});
}
}
在这个代码中,我们首先创建了一个包含多个
Person
对象的列表
people
。然后,我们使用
stream()
方法将列表转换为流,接着使用
filter()
方法进行过滤操作。第一次过滤出年龄大于等于 18 岁的人,第二次过滤出姓名以
G
开头的人。最后,使用
forEach()
方法遍历过滤后的流,并打印出符合条件的人的姓名和年龄。
运行该代码,输出结果如下:
==> Age 18 or greater ==
Henrey - 18
George - 19
Joe - 27
==> Names start with G ==
George - 19
2.7 不同类型的谓词
在 Java 中,Lambda 表达式返回布尔值的也可以称为谓词。除了普通的
Predicate
外,还有其他类型的谓词:
| 谓词类型 | 参数数量 | 参数类型 | 描述 |
| ---- | ---- | ---- | ---- |
|
Predicate
| 1 | 任意类型 | 接受一个参数并返回布尔值 |
|
BiPredicate
| 2 | 任意类型 | 接受两个参数并返回布尔值 |
|
IntPredicate
| 1 |
int
| 接受一个
int
类型的参数并返回布尔值 |
|
LongPredicate
| 1 |
long
| 接受一个
long
类型的参数并返回布尔值 |
3. 总结与应用场景
通过前面的介绍,我们了解了
BigDecimal
类、Lambda 表达式和流的使用。下面我们来总结一下它们的应用场景:
3.1 BigDecimal 类的应用场景
-
金融计算
:在金融领域,对小数的精度要求非常高,
BigDecimal类可以避免浮点数计算带来的精度丢失问题。例如,在银行系统中进行利息计算、货币兑换等操作时,使用BigDecimal类可以确保计算结果的准确性。 -
商业计算
:在商业应用中,如商品价格计算、折扣计算等,也需要精确的小数计算,
BigDecimal类可以满足这些需求。
3.2 Lambda 表达式与流的应用场景
- 数据处理 :当需要对集合中的数据进行过滤、映射、排序等操作时,使用 Lambda 表达式和流可以使代码更加简洁、易读。例如,在一个员工信息管理系统中,需要筛选出年龄大于 30 岁的员工,或者计算所有员工的平均工资等操作,使用流和 Lambda 表达式可以轻松实现。
- 并行处理 :流支持并行处理,可以充分利用多核处理器的性能,提高数据处理的效率。例如,在处理大量数据时,可以使用并行流来加速计算过程。
以下是一个 mermaid 流程图,展示了在实际应用中如何选择使用
BigDecimal
类、Lambda 表达式和流:
graph LR
A[需求场景] --> B{是否需要精确小数计算}
B -- 是 --> C[使用 BigDecimal 类]
B -- 否 --> D{是否需要处理集合数据}
D -- 是 --> E[使用 Lambda 表达式和流]
D -- 否 --> F[使用常规方法]
通过合理使用
BigDecimal
类、Lambda 表达式和流,我们可以提高代码的质量和性能,使程序更加健壮和高效。在实际开发中,我们应该根据具体的需求场景选择合适的技术和方法,以达到最佳的开发效果。
超级会员免费看
2865

被折叠的 条评论
为什么被折叠?



