Lambda表达式能够是一段能够传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为,也就是行为参数化,将不一样的行为做为参数传入方法。java
随着函数式编程思想的引进,Lambda表达式让能够用更加简洁流畅的代码来代替以前冗余的Java代码。express
口说无凭,直接上个例子吧。在Java8以前,关于线程代码是这样的:编程
class Task implements Runnable{ @Override public void run() { System.out.println("Java8 以前 实现Runnable接口中的run方法"); } } Runnable t = new Task();
咱们定义了一个Task类,让它实现Runnable接口,实现仅有的run方法,咱们但愿执行的线程体虽然只有一句话,但咱们仍然花了大量大代码去定义。为了简化,咱们能够采用匿名内部类的方式:数组
Runnable taskBeforeJava8 = new Runnable() { @Override public void run() { System.out.println("Java8 以前的写法, 传入匿名类"); } };
可是,其实仍是不够简洁,咱们用Lambda的写法是这样的:app
// java8 以后 Runnable taskAfterJava8 = () -> System.out.println("Java8 以后的写法,lambda表达式");
咱们仅仅使用()
和->
就完成了这件事,是否是很是简洁呢?若是你以为虽然Lambda写法简洁,可是它的规则让人摸不着头脑,那就跟着我接下去学叭。ide
(parameters) -> action (parameters) -> expression (parameters) -> {statements;}
parameters表明变量,能够为空,能够为单,能够为空,你能想到的方式他均可以。函数式编程
action是实现的代码逻辑部分,能够是一行代码expression
,也能够是一个代码片断statements
。若是是代码片断,须要加上{}
。函数
下面是一些合法的示例,你能够看看有没有掌握:线程
表达式 | 描述 |
---|---|
() -> 1024 |
不须要参数,返回值为1024 |
x -> 2 * x |
接收参数x,返回其两倍 |
(x, y) -> x - y |
接收两个参数,返回它们的差 |
(int x, int y) -> x + y |
接收两个int类型参数,返回他们的和 |
(String s) -> print(s) |
接收一个String对象,并打印 |
什么是函数式接口?函数式接口是只有一个抽象方法的接口,用做lambda表达式的类型。code
@FunctionalInterface // 此注解做用的接口 只能拥有一个抽象方法 public interface Runnable { public abstract void run(); }
在这里,@FunctionalInterface
注解是非必须的,有点相似于@Override
,起强调做用,若是你的接口标注该注解,却没有遵循它的原则,编译器会提示你修改。
JDK原生为咱们提供了一些经常使用的函数式编程接口,让咱们在使用他们编程时,没必要关心接口名,方法名,参数名,只需关注它的参数类型,参数个数,返回值。
接口 | 参数 | 返回值 | 类别 | 示例 |
---|---|---|---|---|
Consumer | T | void | 消费型接口 | 打印输出某个值 |
Supplier | None | T | 供给型接口 | 工厂方法获取一个对象 |
Function | T | R | 函数型接口 | 获取传入列表的总和 |
Predicate | T | boolean | 断言型接口 | 判断是否以summer为前缀 |
/** * 消费型接口, 传入T 无返回值 */ public static void consumerTest() { Consumer<Integer> consumer = num -> System.out.println(num * num); consumer.accept(10); }
/** * 供给型接口, 无参数,返回T */ public static void supplierTest() { Supplier<Object> supplier = () -> new Object(); System.out.println(supplier.get()); }
/** * 断言型 传入参数T ,返回boolean */ public static void predicateTest() { Predicate<String> predicate = name -> name.startsWith("summer"); System.out.println(predicate.test("summerday")); }
/** * 函数型接口 传入T 返回R */ public static void functionTest() { List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); Function<List<Integer>, Integer> function = num -> { int res = 0; for (int n : list) { res += n; } return res; }; Integer num = function.apply(list); System.out.println(num); }
方法引用能够看做特定Lambda表达式的快捷写法,主要分为如下两种:
/** * 方法引用 * 1. 指向静态方法的方法引用 * 2. 指向现有对象的实例方法的方法引用 * * @author Summerday */ public class MethodReferenceTest { public static List<String> getList(List<String> params, Predicate<String> filter) { List<String> res = new LinkedList<>(); for (String param : params) { if (filter.test(param)) { res.add(param); } } return res; } // 静态方法 public static boolean isStartWith(String name) { return name.startsWith("sum"); } public static void main(String[] args) { List<String> params = Arrays.asList("summerday","tqbx","天乔巴夏","summer",""); //静态方法的方法引用 getList(params, name -> MethodReferenceTest.isStartWith(name)); List<String> list = getList(params, MethodReferenceTest::isStartWith); System.out.println(list); // 指向现有对象的实例方法的方法引用 getList(params, name -> name.isEmpty()); List<String> sum = getList(params, String::isEmpty); System.out.println(sum); } }
/** * 数组引用 * @author Summerday */ public class ArrayReferenceTest { public static void main(String[] args) { // 普通lambda Function<Integer,String[]> fun1 = x -> new String[x]; String[] res1 = fun1.apply(10); System.out.println(res1.length); // 数组引用写法 Function<Integer,String[]> fun2 = String[]::new; String[] res2 = fun2.apply(10); System.out.println(res2.length); } }
/** * 构造器引用 * @author Summerday */ public class ConstructorReferenceTest { public static void main(String[] args) { // 普通lambda Supplier<User> sup = () -> new User(); // 构造器引用 Supplier<User> supplier = User::new; User user = supplier.get(); System.out.println(user); } } class User{ }
Predicate,Function,Supplier,Consumer,BinaryOperator
。Classname::method
。