1.基本介绍
lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码:
1.1 两种方式的对比
1.1.1 方式1-匿名内部类
class Student{
    private String name;
    private Double score;

    public Student(String name, Double score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public Double getScore() {
        return score;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "{"
                + "\"name\":\"" + name + "\""
                + ", \"score\":\"" + score + "\""
                + "}";
    }
}:
@Test
public void test1(){
    List<Student> studentList = new ArrayList<Student>(){
        {
            add(new Student("stu1",100.0));
            add(new Student("stu2",97.0));
            add(new Student("stu3",96.0));
            add(new Student("stu4",95.0));
        }
    };
    Collections.sort(studentList, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return Double.compare(o1.getScore(),o2.getScore());
        }
    });
    System.out.println(studentList);
}

代码调用Collections.sort方法对集合进行排序,其中第二个参数是一个匿名内部类,sort方法调用内部类中的compare方法对list进行位置交换,因为java中的参数类型只能是类或者基本数据类型,所以虽然传入的是一个Comparator类,但是实际上可以理解成为了传递compare方法而不得不传递一个Comparator类 ,这种方式显得比较笨拙,而且大量使用的话代码严重冗余,这种情况在java8中通过使用lambda表达式来解决。

lambda表达式专门针对只有一个方法的接口(即函数式接口),Comparator就是一个函数式接口
@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}
@FunctionalInterface的作用就是标识一个接口为函数式接口,此时Comparator里只能有一个抽象方法,由编译器进行判定。
使用lambda表达式之后方式1 中的代码改造如下
 
1.1.2 方式2-lambda表达式
public void test1_(){
        List<Student> studentList = new ArrayList<Student>(){
            {
                add(new Student("stu1",100.0));
                add(new Student("stu2",97.0));
                add(new Student("stu3",96.0));
                add(new Student("stu4",95.0));
            }
        };
        Collections.sort(studentList,(s1,s2)-> Double.compare(s1.getScore(),s2.getScore()));
        System.out.println(studentList);
    }
1.2 lambda语法
1.2.1 多参数
     (1). lambda表达式的基本格式为(x1,x2)->{表达式...};
     (2). 在上式中,lambda表达式带有两个参数,此时参数类型可以省略,但两边的括号不能省略
     (3). 如果表达式只有一行,那么表达式两边的花括号可以省略
1.2.2 无参数
一个常见的例子是新建一个线程,不使用lambda表达式的写法为
public void testThread(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello, i am thread!");
            }
        }).start();
    }
其中Runnable接口也是一个函数式接口,源码如下
@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表达式的写法为
public void testThread_(){
    new Thread(()-> System.out.println("hello, i am thread!")).start();
}
对于没有参数的情况 :
     (1).参数的括号不能省略,
     (2).其他语法同多参数
1.2.3 一个参数
我们构造一个只有一个参数的函数式接口
@FunctionalInterface
public interface MyFunctionalInterface {
    public void single(String msg);
}

/**
 * 需要单个参数
 */
public static void testOnePar(MyFunctionalInterface myFunctionalInterface){
    myFunctionalInterface.single("msg");
}
/**
     * 一个参数,可以省略参数的括号
     */
    @Test
    public void testOneParameter(){
        testOnePar(x-> System.out.println(x));
    }
对于一个参数的情况:
     (1).可以省略参数的括号和类型
     (2).其他语法同多参数
1.3 jdk提供的常用函数式接口
在这里我们为了演示只有一个参数的情况自己创建了一个函数式接口,其实java8中已经为我们提供了很多常见的函数式接口,截图如下:
常见的有
Function:提供任意一种类型的参数,返回另外一个任意类型返回值。 R apply(T t);
Consumer:提供任意一种类型的参数,返回空值。 void accept(T t);
Supplier:参数为空,得到任意一种类型的返回值。T get();
Predicate:提供任意一种类型的参数,返回boolean返回值。boolean test(T t);
因此针对上面的情况,我们可以直接使用Consumer类,
/**
     * 需要单个参数
     */
    public static void testOnePar1(Consumer unaryOperator){
        unaryOperator.accept("msg");
    }
2.方法引用
lambda表达式用于替换函数式接口,方法引用也是如此,方法引用可以使代码更加简单和便捷
2.1 小试牛刀
上代码,根据List中字符串长度排序:
public static void test1_() {
    List<String> strLst = new ArrayList<String>() {
        {
            add("adfkjsdkfjdskjfkds");
            add("asdfasdfafgfgf");
            add("public static void main");
        }
    };
    Collections.sort(strLst, String::compareToIgnoreCase);
    System.out.println(strLst);
}
只要方法的参数和返回值类型与函数式接口中抽象方法的参数和返回值类型一致,就可以使用方法引用。
2.2 使用方式
方法引用主要有如下三种使用情况
     (1). 类::实例方法
     (2). 类::静态方法
     (3). 对象::实例方法
其中后两种情况等同于提供方法参数的lambda表达式,
如System.out::println 等同于(x)->System.out.println(x),
   Math::pow 等同于(x,y)->Math.pow(x,y).
第一种中,第一个参数会成为执行方法的对象,String::compareToIgnoreCase)等同于(x,y)->x.compareToIgnoreCase(y)
此外,方法引用还可以使用this::methodName及super::methodName表示该对象或者其父类对象中的方法
class Father {
    public void greet() {
        System.out.println("Hello, i am function in father!");
    }
}

class Child extends Father {
    @Override
    public void greet() {
        Runnable runnable = super::greet;
        new Thread(runnable).start();
    }
}
public static void main(String[] args){
        new Child().greet();
    }
最后打印的结果为:Hello, i am function in father!
3.构造器引用
构造器引用同方法引用类似,同样作用于函数式接口
构造器引用的语法为 ClassName::new
啥也不说,线上代码
List<String> labels = Arrays.asList("aaa","bbb","ccc","ddd");
Stream<Button> buttonStream = labels.stream().map(Button::new);
如上代码所示,map方法内需要一个Function对象
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
调用Button的构造器,接收一个String类型的参数,返回一个Button类型的对象
public class Button extends ButtonBase {

        /**
         * Creates a button with the specified text as its label.
         *
         * @param text A text string for its label.
         */
        public Button(String text) {
            super(text);
            initialize();
        }
    }
另外一个例子如下
Button[] buttons1 = buttonStream.toArray(Button[]::new);
toArray方法的申明如下
<A> A[] toArray(IntFunction<A[]> generator);
接收一个IntFunction类型的接口R apply(int value);该接口接收一个int型参数,返回指定类型
调用数组的初始化方法刚好适合。
有一个简单的构造器引用的例子如下:
public class LambdaTest3 {

    @Test
    public void test1_(){
        List<Integer> list = this.asList(ArrayList::new ,1,2,3,4,5);
        list.forEach(System.out::println);
    }

    public  <T> List<T> asList(MyCrator<List<T>> creator,T... a){
        List<T> list =  creator.create();
        for (T t : a)
            list.add(t);
        return list;
    }
}
interface MyCrator<T extends List<?>>{
    T create();
}
我们在项目中经常使用asList来创建一个ArrayList,但是也只能是ArrayList,
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
我们如何在asList中指定创建哪种类型的List的实例呢,使用构造器引用使得asList方法可以指定生成的List类型。
4.自由变量的作用范围
啥都不说,上代码先:
public class LambdaTest4 {
    public void doWork1(){
        Runnable runnable = ()->{
            System.out.println(this.toString());
            System.out.println("lambda express run...");
        };
        new Thread(runnable).start();
    }

    public void doWork2(){
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(this.toString());
                System.out.println("anony function run...");
            }
        };
        new Thread(runnable).start();
    }
    public static void main(String[] args) {
        new LambdaTest4().doWork1();
        new LambdaTest4().doWork2();
    }
}
代码中doWork1和doWork2分别使用lambda表达式和匿名内部类的方式实现了Runnable接口,最后打印的结果如下
com.java8.lambda.LambdaTest4@74f84cf
lambda express run...
com.java8.lambda.LambdaTest4$1@4295c176
anony function run...
可见使用lambda表达式的方式,表达式中的this指的是包含lambda表达式的类,而使用匿名内部类的方式,this指的是匿名内部类本身。
4.1 自由变量和闭包
lambda达式中的变量有几类,1.参数内的变量,2.lambda表达式中的内部变量,3.自由变量,自由变量指的是在lambda表达式之外定义的变量。
包含自由变量的代码则称为闭包,如果理解了lambda表达式会在编译阶段被转换为匿名内部类,那么可以很容易理解自由变量在lambda表达式中的作用范围,在lambda表达式中会捕获所有的自由变量,并且将变量定义为final类型,所以不能改变lambda表达式中自由变量的值,如果改变,那么首先就无法编译通过。
对于引用类型(如ArrayList),final指的是引用指向的类始终不变,进行add操作是允许的,但是应该保证变量的线程安全。
代码如下所示:
public class Outer {
    public AnnoInner getAnnoInner(int x) {
        int y = 100;
        return new AnnoInner() {
            int z = 100;

            @Override
            public int add() {
                return x + y + z;
            }
        };
    }

    public AnnoInner AnnoInnergetAnnoInner1(List<Integer> list1) {
        List<Integer> list2 = new ArrayList<>(Arrays.asList(1, 2, 3));
        return ()->{
            list2.add(123);
            int count = 0;
            Iterator<Integer> it = list1.iterator();
            while (it.hasNext()){
                count+=it.next();
            }
            Iterator<Integer> it1 = list2.iterator();
            while (it1.hasNext()){
                count+=it1.next();
            }
            return count;
        };
    }

    @Test
    public void test(){
        AnnoInner res = new Outer().AnnoInnergetAnnoInner1(new ArrayList<>(Arrays.asList(1,2,3)));
        System.out.println(res.add());
    }

}

interface AnnoInner {
    int add();
}
最后返回135
5.接口的静态方法和默认方法
java8对于接口做出了种种改进,使得我们可以在接口中实现默认方法和静态方法,见Comparator接口完整定义
@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);

    boolean equals(Object obj);

    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

    default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }

    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        return thenComparing(comparing(keyExtractor));
    }

    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
        return thenComparing(comparingInt(keyExtractor));
    }

    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
        return thenComparing(comparingLong(keyExtractor));
    }

    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        return thenComparing(comparingDouble(keyExtractor));
    }

    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        return Collections.reverseOrder();
    }

    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }

    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }

    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(false, comparator);
    }

    public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        Objects.requireNonNull(keyExtractor);
        Objects.requireNonNull(keyComparator);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                              keyExtractor.apply(c2));
    }

    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
    }

    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
    }

    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
    }
}
在比较器接口中定义了若干用于比较和键提取的静态方法和默认方法,默认方法的使用使得方法引用更加方便,例如使用java.util.Objects类中的静态方法isNull和nonNull可以在Stream中很方便的进行null的判定(之后会有对于stream的介绍)。但是在接口中引入默认方法设计到一个问题,即
(1).接口中的默认方法和父类中方法的冲突问题
(2).接口之间引用的冲突问题
对于第一个冲突,java8规定类中的方法优先级要高于接口中的默认方法,所以接口中默认方法复写Object类中的方法是没有意义的,因为所有的接口都默认继承自Object类使得默认方法一定会被覆盖。
对于第二个冲突,java8强制要求子类必须复写接口中冲突的方法。如下所示:
public class LambdaTest5 implements myInterface1, myInterface2 {
    @Override
    public void getName() {
        myInterface1.super.getName();
    }

    public static void main(String[] args) {
        new LambdaTest5().getName();
    }
}

interface myInterface1 {
    default void getName() {
        System.out.println("myInterface1 getName");
    }

    ;
}

interface myInterface2 {
    default void getName() {
        System.out.println("myInterface2 getName");
    }
}
强制使用myInterface1中的getName方法
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

java8之lambda表达式入门的更多相关文章

  1. Java Lambda表达式入门

    Java Lambda表达式入门 http://blog.csdn.net/renfufei/article/details/24600507 Java 8十个lambda表达式案例 http://w ...

  2. Java8中Lambda表达式的10个例子

    Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 //Before Java 8: new Thread(new Runnable() { @Overri ...

  3. java8中lambda表达式的应用,以及一些泛型相关

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...

  4. java8之lambda表达式(1)-基本语法

    lambda表达式,即带有参数的表达式,为更清晰地理解lambda表达式,先看如下例子: (1) class Student{ private String name; private Double ...

  5. JAVA8之lambda表达式具体解释,及stream中的lambda使用

    前言: 本人也是学习lambda不久,可能有些地方描写叙述有误,还请大家谅解及指正! lambda表达式具体解释 一.问题 1.什么是lambda表达式? 2.lambda表达式用来干什么的? 3.l ...

  6. Lambda表达式入门

    Lambda表达式是Java 8的重要更新,也是一个被广大开发者期待已久的新特性,Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接 ...

  7. Java Lambda表达式入门[转]

    原文链接: Start Using Java Lambda Expressions http://blog.csdn.net/renfufei/article/details/24600507 下载示 ...

  8. Android Stutio中使用java8的Lambda表达式

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51532028 本文出自:[openXu的博客] 目录: 为什么要使用Lambda表达式 让A ...

  9. Java8之Lambda表达式基础

    Java 8中,将会提供对lambda的支持,函数式编程FP(Functional Programming)将会得到很好地支持,而函数式编程的一个重要特点就是适合并行运算. λ:希腊字母表中排序第十一 ...

随机推荐

  1. MVC Api 的跨项目路由

    现有Momoda.Api项目,由于团队所有人在此项目下开发,导致耦合度太高,现从此接口项目中拆分出多个子项目从而避免对Momda.Api的改动导致“爆炸” MVCApi的跨项目路由和MVC有解决方式有 ...

  2. VBA编程常用语句

    .Option Explicit '强制对模块内所有变量进行声明 Option Private Module '标记模块为私有,仅对同一工程中其它模块有用,在宏对话框中不显示 Option Compa ...

  3. Microsoft Visual Studio 2013 Update 5 direct download link for full ISO

    From:http://www.nickdu.com/?p=604 Visual Studio 2013 Update 5 is now released and maybe you are also ...

  4. html狂记

    由于承接一部分站点优化工作,竟无节操地好几天没有喂博客,好了,今天完成交接工作,马上奉上DIV+CSS传统开发的干货一枚,内容绝非原创,仅是收集.学习.消化.总结.吐出... 基本结构标签: < ...

  5. [转]精通JS正则表达式

    原文路径:http://www.jb51.net/article/25313.htm 正则表达式可以: •测试字符串的某个模式.例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式 ...

  6. svn使用--all-static编译,移植到其它系统上可能使setlocale等GLIBC相关库函数调用失败

    svn: Can't convert string from 'UTF-8' to native encoding

  7. 在一周内学会使用 AUTO CAD

    学习目的: 1.使用AUTO CAD绘制电路板外框.元器件封装: 2.借助软件使用,对产品结构有更深入的体会. 学习过程: 1.由于本人急需在短时间内具备简单的二维绘图能力,故没有借鉴.对比网络上其他 ...

  8. [LintCode] Segment Tree Build 建立线段树

    The structure of Segment Tree is a binary tree which each node has two attributes start and end deno ...

  9. SAP RFC通信模式

    在网络技术中,数据通信可以大致划分为两种基本模式:同步通信和异步通信. 其本义是:异步通信时,通信双方时钟允许存在一定误差:同步通信时,双方时钟的允许误差较小.在SAP的系统间的通信过程中,也借用术语 ...

  10. THE ARCHITECTURE OF COMPLEXITY HERBERT A. SIMON* Professor of Administration, Carnegie Institute of Technology (Read April 26, 1962)

    THE ARCHITECTURE OF COMPLEXITY HERBERT A. SIMON* Professor of Administration, Carnegie Institute of ...