语法基础
java8中lambda表达式主要用来解决java中函数式编程语法太拖沓。
什么是函数式编程呢,我们来看个例子。
下面的代码是根据字符串长度来排序
List<String> strs = new ArrayList<>();
strs.add("123");
strs.add("123456");
strs.add("12");
Collections.sort(strs, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
Collections.sort第二个参数是排序规则,在js中可以通过传递函数来实现,java中不允许直接传递函数,只能通过匿名内部类来实现,但是代码就显得很冗余,再来看看lambda的实现方式
//不需要new对象了,省略了方法名
Collections.sort(strs, (String s1, String s2) -> {
return Integer.compare(s1.length(), s2.length());
});
//lambda支持类型推断,参数不需要写类型
Collections.sort(strs, (s1, s2) -> {
return Integer.compare(s1.length(), s2.length());
});
//方法体里面只有单行代码可以省略括号,return和分号
Collections.sort(strs, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
可以看到,通过层层省略只需要一行代码就能实现了
函数式接口
什么是函数式接口呢?接口里面只有一个方法的就是函数式接口,只有函数式接口才能使用lambda表达式!
java8提供了很多内置函数式接口供开发者使用,常用的是以下几个
消费型接口可以实现你提供一种资源,具体如何使用资源由调用方决定,比如你女朋友要买东西,你只需要提供钱包即可,具体买什么由你女朋友决定
@Test
public void testComsumer() {
//如果参数只有一个可以省略括号
buy(money -> System.out.println(StrUtil.format("你的女朋友拿到{}元,消费{}元", money, 5)));
}
public void buy(Consumer<Integer> consumer) {
int money = 10; //你的钱包,真实环境中应该是个对象
consumer.accept(money);//把你的钱包交给你女朋友消费
}
供给型正好相反,调用方提供资源,由你决定如何使用资源,比如你们公司福利比较好,每天下午有免费饮料可以喝,但是喝什么饮料完全是随机的
@Test
public void testDrink() {
//公司随机提供一款饮料
String[] drinks = new String[]{"奶茶", "咖啡", "旺仔牛奶"};
drink(() -> drinks[RandomUtil.randomInt(drinks.length)]);
}
public void drink(Supplier<String> supplier) {
//获取到饮料
String drink = supplier.get();
//开始喝
System.out.println("我今天喝的饮料是" + drink);
}
函数型顾名思义,可以提供一种映射关系,把一种输入转换成另一种输出,比如把数组里的数值都乘以2输出,具体如何转换由调用方决定,算是策略模式的一种变形
@Test
public void testTransform() {
List<String> numbers = new ArrayList<>();
numbers.add("111");
numbers.add("222");
numbers.add("333");
//提供转换策略,输出[111, 222, 333]
List<Integer> intNum = transform(numbers, item -> Integer.parseInt(item));
System.out.println(intNum);
//提供转换策略,输出[222, 444, 666]
List<Integer> multiNum = transform(numbers, item -> Integer.parseInt(item) * 2);
System.out.println(multiNum);
}
//T是输入类型,R是输出类型
public <T, R> List<R> transform(List<T> input, Function<T, R> transform) {
List<R> output = new ArrayList<>();
for (T item : input) {
output.add(transform.apply(item));
}
return output;
}
断定型就很简单了,可以用来做过滤,具体的过滤策略可以由调用方提供
@Test
public void testFilter() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//调用方提供过滤策略,返回大于2的值
list = filter(list, item -> item > 2);
//输出3
System.out.println(list);
}
public List<Integer> filter(List<Integer> list, Predicate<Integer> predicate) {
List<Integer> returnList = new ArrayList<>();
for (Integer item : list) {
//满足条件的返回
if (predicate.test(item)) {
returnList.add(item);
}
}
return returnList;
}
方法引用
方法引用的格式为 类::方法名,是lambda的一种简写形式
//这个消费型接口用来打印获取到的字符串
Consumer<String> consumer = s -> System.out.println(s);
//等价上面的代码,参数和箭头可以省略,打印的参数就是s
consumer = System.out::println;