java8新特性之 Lambda表达式
一、适用场合
当使用匿名内部类实现接口,并且接口中有且仅有一个抽象方法时可以使用Lambda表达式。
二、Lambda表达式的写法
Lambda表达式分三部分构成:
() -> {}
中间的 “->” 是Lambda操作符又称箭头操作符;
Lambda操作符左边的“()”中填写Lambda表达式的参数列表;
Lambda操作符左边的“{}”中填写Lambda表达式的方法实现,一般称为Lambda体。
语法规则1:无参数,无返回值
以创建一个新线程为例,使用匿名内部类时的写法:
@Test
public void newThread(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("创建了一个新线程!!");
}
};
runnable.run();
}
使用Lambda表达式创建一个新线程:
@Test
public void newThreadByLambda(){
Runnable runnable = () -> {System.out.println("创建了一个新线程!!!");};
runnable.run();
}
当Lambda表达式方法体中只有一行代码时,“{}”是可以省略不写的,所以也可这样写:
@Test
public void newThreadByLambda(){
Runnable runnable = () -> System.out.println("创建了一个新线程!!!");
runnable.run();
}
语法规则2:一个参数,无返回值
以Java8中自带的函数式接口Consumer为例:
(注:函数式接口的定义下文会提到)
@Test
public void lambdaTest1(){
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("苏苏可真帅啊!!!");
}
与Lambda体的“{}”类似,当参数只有一个时,参数的“()” 也可以省略,故以上代码还可以这样写:
@Test
public void lambdaTest1(){
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("苏苏可真帅啊!!!");
}
语法规则3:多个参数,有返回值,并且Lambda体中有多行
以Java8中的函数接口BiPredicate为例:
@Test
public void lambdaTest(){
BiPredicate<String,String> biPredicate = (x, y) ->{
boolean a = x.equalsIgnoreCase(y);
return a;
};
System.out.println(biPredicate.test("hello","Hello"));
System.out.println(biPredicate.test("hello","world"));
}
Lambda表达式中参数的数据类型可以不写,比如上面的例子中x和y的数据类型String就省略了
三、函数式接口
Lambda表达式的函数式编程需要函数式接口的支持。
函数式接口的定义:接口中只有一个抽象方法的接口叫函数式接口
函数式接口可以使用@FunctionalIterface注解标识。
定义一个函数式接口:
@FunctionalInterface
public interface myService<T> {
Object getValue(T t);
}
调用自定义的函数式接口:
public String stringHandler(String s,MyService<String> myService){
return (String) myService.getValue(s);
}
@Test
public void test6(){
MyService<String> myService = x -> x.toUpperCase();
System.out.println(myService.getValue("oh no!"));
String result = stringHandler("a ha!",x -> x.toUpperCase());
System.out.println(result);
}
四、Java8中内置的函数式接口
为了防止使用Lambda表达式时都必须手动添加接口,Java8内置了四大核心函数式接口:
/*
* Consumer<T> :消费型接口
* 参数类型:T
* 返回类型:void
* void acept(T t);
*
* Supplier<T> :供给型接口
* 参数类型:无
* 返回类型:T
* T get();
*
* Function<T,R> :函数型接口
* 参数类型:T
* 返回类型:R
* R apply(T t);
*
* Predicate<T> :断言型接口
* 参数类型:T
* 返回类型:boolean
* boolean test(T t);
消费型接口
//打印出消费了多少钱
public void cost(Double d, Consumer<Double> consumer){
consumer.accept(d);
}
@Test
public void test1(){
cost(998.00,x -> System.out.println("苏苏去超市购物消费" + x + "元!!!!"));
}
供给型接口
//产生指定个数的整数,并放入List中
public List<Integer> getNumList(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = supplier.get();
list.add(n);
}
return list;
}
@Test
public void test2(){
List<Integer> list = getNumList(10,() -> (int)Math.random());
System.out.println(list);
}
函数型接口
//处理字符串
public String strHandler(String s, Function<String,String> function){
return function.apply(s);
}
@Test
public void test3(){
//将字符串转换成大写
String strUpper = strHandler("insuonante",x -> x.toUpperCase());
System.out.println(strUpper);
}
断言型接口
//输入数字,判断是否大于0
@Test
public void test4(){
Predicate<Integer> predicate = (x) -> x > 0;
System.out.println(predicate.test(10));
}
其他内置接口
BiFunction< T, U, R >
BiConsumer< T, U >
BinaryOperator< T >
...
五、引用
三种方法引用写法:
对象::实例方法
@Test
public void test(){
Consumer<String> consumer = System.out::println;
consumer.accept("到饭点了,我真的好饿啊!");
}
类::静态方法
@Test
public void test(){
Consumer<Integer> consumer = String::valueOf;
consumer.accept(1);
}
类::实例方法
@Test
public void test(){
Consumer<String> consumer = String::trim;
consumer.accept(" 到饭点了,我真的好饿啊! ");
}
构造器引用: ClassName::new
@Test
public void test(){
Supplier<String> supplier = String::new;
System.out.println(supplier.equals("到饭点了,我真的好饿啊!"));
}
数组引用:Type::new
@Test
public void test(){
Function<Integer,String[]> function = String[]::new;
String[] strings = function.apply(20);
System.out.println(strings.length);
}