流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现),可以把它们看成遍历数据集的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码!
假设有一张名字为菜品的数据库表,要查询卡路里低于400的菜品名称,并且菜品名称需要按照卡路里排序,要怎么做?
SQL 语句如下:
SELECT name FROM dishes WHERE calorie < 400 ORDER BY calorie ASC;
如上,你不需要实现如何根据菜肴的属性进行筛选(比如利用迭代器和累加器),你只需要表达你想要什么。
Dish 类
//菜肴
public class Dish {
//名称
private final String name;
//是否素食
private final boolean vegetarian;
//卡路里
private final int calories;
//类型
private final Type type;
//菜品类型(肉,鱼,其他)
public enum Type {MEAT, FISH, OTHER}
public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
}
实现:
public class DishTest1 {
public static final List menu = Arrays.asList(
new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
//季节水果
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
//虾
new Dish("prawns", false, 300, Dish.Type.FISH),
//鲑鱼,三文鱼,
new Dish("salmon", false, 450, Dish.Type.FISH));
public static List filterDishByCalories() {
// 1.筛选低卡路里的菜品
List lowCaloricDishes = new ArrayList<>();
for (Dish dish : menu) {
if (dish.getCalories() < 400) {
lowCaloricDishes.add(dish);
}
}
// 2.对菜品排序
Collections.sort(lowCaloricDishes, new Comparator() {
@Override
public int compare(Dish o1, Dish o2) {
return o1.getCalories() - o2.getCalories();
}
});
// 3.取出菜品名称
List lowCaloricDishesName = new ArrayList<>();
for (Dish dish : lowCaloricDishes) {
lowCaloricDishesName.add(dish.getName());
}
return lowCaloricDishesName;
}
public static void main(String[] args) {
List lowCaloricDishesName = filterDishByCalories();
System.out.println(lowCaloricDishesName);
}
}
结果:
[season fruit, prawns, rice]
如上,这种方式称为外部迭代,操作较繁琐,在这段代码中,使用了一个“垃圾变量”lowCaloricDishes。它唯一的作用就是作为一次性的中间容器。
如下,代码见名知意,使用者只需要关心做什么,怎么做由 Streams库 内部迭代 帮我们把迭代做了
public static List filterDishByCaloriesWithStreamAPI() {
return menu.stream()
.filter(dish -> dish.getCalories() < 400)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(Collectors.toList());
}
对于大数据量,也可以使用并行处理,如下:
return menu.parallelStream()
.filter(dish -> dish.getCalories() < 400)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(Collectors.toList());
使用 Stream API 好处如下:
声明性——更简洁,更易读
可复合——更灵活
可并行——性能更好
参考:《Java 8 实战》