Lambda表达式可以简洁地表示可传递的匿名函数的一种方式
匿名:没有明确的名称
函数:Lambda函数不像方法那样属于某个特定的类
传递:可以作为参数传递给方法或存储在变量中
简洁:无需像匿名类那样写很多模板代码
@FunctionalInterface
public interface Predicate{
boolean test(T t);
}
@FunctionalInterface
public interface Consumer{
void accept(T t);
}
@FunctionalInterface
public interface Function{
R apply(T t);
}
package cn.iponkan.lambda;
import java.math.BigDecimal;
/**
* 定义实体类
*
* @author dongtangqiang
*/
public class Apple {
/**
* 颜色
*/
private String color;
/**
* 重量
*/
private BigDecimal weight;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public BigDecimal getWeight() {
return weight;
}
public void setWeight(BigDecimal weight) {
this.weight = weight;
}
}
package cn.iponkan.lambda;
import java.util.Comparator;
/**
* 实现比较器接口
*
* @author dongtangqiang
*/
public class AppleComparator implements Comparator {
@Override
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
}
package cn.iponkan.lambda;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static java.util.Comparator.comparing;
/**
* Lambda表达式测试
*
* @author dongtangqiang
*/
public class TestLambda {
public static void main(String[] args) {
List inventory = new ArrayList<>();
increaseInventory(inventory);
// 实现对库存的排序
// ①定义类实现比较器接口
inventory.sort(new AppleComparator());
// ②使用匿名类
inventory.sort(new Comparator() {
@Override
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
});
// ③使用Lambda表达式
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
// Comparator具有一个叫作comparing的静态辅助方法,
//它可以接受一个Function来提取Comparable键值,并生成一个Comparator对象
inventory.sort(comparing((a) -> a.getWeight()));
// ④使用方法引用
inventory.sort(comparing(Apple::getWeight));
}
private static void increaseInventory(List inventory) {
Apple a1 = new Apple();
a1.setColor("red");
a1.setWeight(BigDecimal.valueOf(120));
inventory.add(a1);
Apple a2 = new Apple();
a2.setColor("green");
a2.setWeight(BigDecimal.valueOf(160));
inventory.add(a2);
Apple a3 = new Apple();
a3.setColor("red");
a3.setWeight(BigDecimal.valueOf(155));
inventory.add(a3);
}
}
流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不
是临时编写一个实现)。
Java 8中的集合支持一个新的stream方法,它会返回一个流(接口定义在java.util.stream.Stream里)。
“从支持数据处理操作的源生成的元素序列”。
流的两个特点
流只能遍历一次
流是内部迭代,不需要像for-each,或使用iterator这样来显示迭代操作。内部迭代时,项目可以透明地并行处理,或者用更优化的顺序进行处理。
使用谓词筛选
筛选各异的元素
截短流
跳过元素
对流中每一个元素应用函数
流的扁平化
// 流的扁平化
List words = Arrays.asList("Hello", "World");
List uniqueCharacters = words.stream()//
.map(w -> w.split(""))//
.flatMap(Arrays::stream)
.distinct()
.collect(toList());
menu.stream().anyMatch(Dish::isVegetarian)
boolean isHealthy = menu.stream()
.allMatch(d -> d.getCalories() < 1000);
boolean isHealthy = menu.stream()
.noneMatch(d -> d.getCalories() >= 1000);
findAny方法将返回当前流中的任意元素
findFirst找到第一个元素
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
// 使用方法引用
int sum = numbers.stream().reduce(0, Integer::sum);
reduce接受两个参数:
最大值和最小值
Optional max = numbers.stream().reduce(Integer::max);
Optional max = numbers.stream().reduce(Integer::min);
Integer count = menu.stream()//
.map(d -> 1)// 把每一个元素映射成1
.reduce(0, Integer::sum);//统计
// 或者
long count = menu.stream().count();
IntStream、DoubleStream和LongStream,分别将流中的元素特化为int、long和double,从而避免了暗含的装箱成本。每个接口都带来了进行常用数值归约的新方法,比如对数值流求和的sum,找到最大元素的max。此外还有在必要时再把它们转换回对象流的方法。
映射到数值流
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum();
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream stream = intStream.boxed();
IntStream evenNumbers = IntStream.rangeClosed(1, 100)
.filter(n -> n % 2 == 0);
Stream stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
Stream.generate(Math::random) //Supplier类型的Lambda提供新的值
.limit(5)
.forEach(System.out::println);
package cn.iponkan.stream;
/**
* 实体类定义
*
* @author dongtangqiang
*/
public class Dish {
private final String name;
/**
* 荤素
*/
private final boolean vegetarian;
private final int calories;
private final Type type;
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;
}
@Override
public String toString() {
return name;
}
public enum Type {MEAT, FISH, OTHER}
}
package cn.iponkan.stream;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.Collectors.toList;
/**
* @author dongtangqiang
*/
public class TestStream {
public static void main(String[] args) {
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));
// 流的使用初体验
List threeHighCaloricDishNames = menu.stream()// 建立流水线
.filter(d -> d.getCalories() > 300) //选取高热量菜肴
.map(Dish::getName)//获取菜名
.limit(3)//只取前三条
.collect(toList());//将结果保存到集合中
System.out.println(threeHighCaloricDishNames); // [pork, beef, chicken]
// 用流筛选前两个荤菜
List twoNotVegetarianDishList = menu.stream()//
.filter(d -> d.getType() == Dish.Type.MEAT) //
.limit(2)//
.collect(toList());
// 获取菜肴的名称:
List dishNames = menu.stream()//
.map(Dish::getName)// 返回 Stream
.map(String::length)//
.collect(toList());
}
}
long howManyDishes = menu.stream().collect(Collectors.counting());
Comparator dishCaloriesComparator =
Comparator.comparingInt(Dish::getCalories);
Optional mostCalorieDish =
menu.stream()
.collect(maxBy(dishCaloriesComparator));
// 求出菜单列表的总热量
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
IntSummaryStatistics menuStatistics =
menu.stream().collect(summarizingInt(Dish::getCalories));
String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));
int totalCalories = menu.stream().collect(reducing(0, Dish::getCalories, (i, j) -> i + j));
reducing方法它需要三个参数
reducing方法可以传单个参数
要实现多级分组,我们可以使用一个由双参数版本的Collectors.groupingBy工厂方法创建的收集器,它除了普通的分类函数之外,还可以接受collector类型的第二个参数。
把收集器的结果转换为另一种类型
…未完待续