感受Lambda表达式写起来确实很简洁,今天就简单看了一下Lambda表达式。在Java 8,一个重要的变动是引入Lambda表达式(lambda expression
),这听起来彷佛很牛,有种我虽然不知道Lambda表达式是什么,但我仍然以为很厉害的感受。具体到语言层面上Lambda表达式不过是一种新的语法而已,下面就一块儿敲开Java函数式编程的大门。html
到底什么是Lambda表达式、什么是函数式编程。先来看一下Java 8新的语法特性带来的便利之处,相信你会受益不浅。java
不用Lambda表达式新起一个线程,以下:git
new Thread(new Runnable() { @Override public void run() { System.out.println("thread second run test"); } }).start();
用Lambda表达式就由能够这样写:github
new Thread( () -> System.out.println("Thread first run()") ).start();
能够看出,匿名类消失了。可见,lambda expression一个常见的用法是取代(某些)匿名内部类,但Lambda表达式的做用不限于此。web
//能够放多行代码 以 大括号扩起 new Thread( () -> { System.out.println("Thread test111"); System.out.println("Thread test222"); } ).start();
因此,就有以下:express
Runnable run = () -> System.out.println("Hello World"); ActionListener listener = event -> System.out.println("test clicked");// 2 Runnable multiLine = () -> {// 3 System.out.println("Hi "); System.out.println("boy"); }; BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4 BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5
表面上看起来每一个Lambda表达式都是原来匿名内部类的简写形式,该内部类实现了某个函数接口(Functional Interface
),但事实比这稍微复杂一些,这里再也不展开。所谓函数接口是指内部只有一个接口函数的接口。Java是强类型语言,不管有没有显式指明,每一个变量和对象都必须有明确的类型,没有显式指定的时候编译器会尝试肯定类型。Lambda表达式的类型就是对应函数接口的类型。编程
好比,Runnable的函数式注解以下:api
@FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
Lambda表达式的另外一个重要用法,是和Stream一块儿使用。Stream is a sequence of elements supporting sequential and parallel aggregate operations。Stream就是一组元素的序列,支持对这些元素进行各类操做,而这些操做是经过Lambda表达式指定的。能够把Stream看做Java Collection的一种视图,就像迭代器是容器的一种视图那样(但Stream不会修改容器中的内容)。下面例子展现了Stream的常见用法。oracle
例1:ide
假设须要从一个字符串列表中选出以数字开头的字符串并输出,Java 8以前须要这样写:
List<String> list = Arrays.asList("1one", "two", "three", "4four"); for(String str : list){ if(Character.isDigit(str.charAt(0))){ System.out.println(str); } }
而在Java 8就能够这样写:
strList.stream()// 1.获得容器的Steam .filter(str -> Character.isDigit(str.charAt(0)))// 2.选出以数字开头的字符串 .forEach(str -> System.out.println(str));// 3.输出字符串
上述代码首先1. 调用List.stream()
方法获得容器的Stream,2. 而后调用filter()
方法过滤出以数字开头的字符串,3. 最后调用forEach()
方法输出结果。
例2:
假设须要从一个字符串列表中,选出全部包含own的字符串,将其转换成大写形式,并把结果放到新的集合当中。
java8以前的代码我就不写了,直接用java8看吧,具体以下:
List<String> testList = Arrays.asList("1owne", "twown", "three", "4fownur"); Set<String> newList = testList.stream()// 1.获得容器的Stream .filter(str -> str.contains("o"))// 2.选出不以数字开头的字符串 .map(String::toUpperCase)// 3.转换成大写形式 .collect(Collectors.toSet());// 4.生成结果集 newList.stream().forEach(str -> System.out.println(str));//5.输出结果
上述代码首先
1. 调用List.stream()方法获得容器的Stream,
2. 而后调用filter()方法选出不以数字开头的字符串,
3. 以后调用map()方法将字符串转换成大写形式,
4. 最后调用collect()方法将结果转换成Set。
5. 用forEach输出结果。
例子中还展现了方法引用(method references,代码中标号3处)以及收集器(Collector,代码中标号4处)的用法,这里再也不展开,有兴趣能够自行查资料看看。
经过这个例子咱们看到了Stream链式操做,即多个操做能够连成一串。不用担忧这会致使对容器的屡次迭代,由于不是每一个Stream的操做都会当即执行。Stream的操做分红两类,一类是中间操做(intermediate operations
),另外一类是结束操做(terminal operation
),只有结束操做才会致使真正的代码执行,中间操做只会作一些标记,表示须要对Stream进行某种操做。这意味着能够在Stream上经过关联多种操做,但最终只须要一次迭代。
能够看出,Stream的明显优点:
github测试代码:https://github.com/wangtao1/functional-lambda.git
借阅:
1.https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html 2.http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html 3.https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html