JAVA8 Lambda表达式完全解析

JAVA8 新特性

在学习JAVA8 Lambda之前,必须先了解一下JAVA8中与Lambda相关的新特性,不然对于一些概念会感到比较陌生。

1、 接口的默认方法和静态方法

Java 8允许我们给接口添加一个默认方法,用default修饰即可。默认方法可以重写,也可以不用重写。这就是和抽象方法的区别,在用法上,没有其他区别。

public interface IMyInterface {
    void onMethond(String str);//这是一个抽象方法
    default String onDefalutMethod(){//这是一个默认方法
        return "这是一个默认方法";
    }
}
//重写默认方法
public class MyImpl1 implements IMyInterface {

    @Override
    public void onMethond(String str) {
        // TODO Auto-generated method stub

    }
    @Override
    public String onDefalutMethod() {
        return "重写默认方法";
    }

}
//不重写默认方法
public class MyImpl2 implements IMyInterface {

    @Override
    public void onMethond(String str) {
        // TODO Auto-generated method stub
    }
}

此外Java 8还允许我们给接口添加一个静态方法,用static修饰即可。

public interface IMyInterface {

    void onMethond(String str);//这是一个抽象方法

    default String onDefalutMethod(){//这是一个默认方法
        return "这是一个默认方法";
    }

    static String onStaticMethod(){
        return "这是一个静态方法";
    }

}

2、 函数式接口(Functional Interface)

什么叫函数式接口?他和普通接口有什么区别?

“函数式接口”是指仅仅只包含一个抽象方法的接口(可以包含默认方法和静态方法),其他特征和普通接口没有任何区别,Java中Runnalbe,Callable等就是个函数式接口;。我们可以给一个符合函数式接口添加@FunctionalInterface注解,这样就显式的指明该接口是一个函数式接口,如果不是,编译器会直接提示错误。当然你也可以不用添加此注解。添加的好处在于,由于Lambda表达式只支持函数式接口,如果恰好这个接口被应用于Lambda表达式,某天你手抖不小心添加了个抽象方法,编译器会提示错误。

//显式指明该接口是函数式接口
@FunctionalInterface
public interface IMyInterface {

    void onMethond(String str);//这是一个抽象方法

    default String onDefalutMethod(){//这是一个默认方法
        return "这是一个默认方法";
    }

    static String onStaticMethod(){
        return "这是一个静态方法";
    }

}

3、方法与构造函数引用

Java 8 允许你使用::关键字来引用已有Java类或对象的方法或构造器。::的诞生和Lambda一样都是来简化匿名内部类的写法的,所以::必须配合函数式接口一起用。使用::操作符后,会返回一个函数式接口对象,这个接口可以自己定义,也可以直接使用系统提供的函数式接口,系统提供的后面会单独介绍。请注意,这一节的内容会让你觉得这些用法蛋疼无比,这是因为还没有开始介绍Lambda表达式,::和Lambda结合使用才是王道,希望你还能坚持到介绍Lambda表达式^_^。

假如有个Person类如下,以下的例子都以这个Person类为基础讲解。

public class Person {
    private String name;
    private int age;

    public Person(){

    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

   public static String show(String str){
        System.out.println("----->输入"+str);
        return "----->返回"+str;
    }
}
  • 使用::关键字初始化构造函数,返回的是一个函数式接口,这个接口可以自己定义,也可以直接使用系统提供的函数式接口。现在先来定义一个函数式接口
@FunctionalInterface
public interface PersonSupply {
    Person get();
}
PersonSupply sp=Person::new;
Person person=sp.get();

PersonSupply sp=Person::new;等价于下面

PersonSupply sp=new PersonSupply{

  public Person get(){
      Person person=new Person();
      return person;
  }
}

怎么定义这个函数式接口呢?首先我们要看::后面,可知,默认构造不需要参数,所以我们的get()定义为无参,但是我们需要Person对象,所以返回值为Person。

当然为了使这个接口更通用,我们可以定义成如下形式

@FunctionalInterface
public interface PersonSupply<T> {
    T get();
}

PersonSupply<Person> sp=Person::new;
Person person=sp.get();

java自带Supplier的接口就是这样的,后面会做介绍。直接使用Supplier如下

Supplier<Person> sp=Person::new;
Person person=sp.get();

怎么初始化带参构造函数?

首先写一个函数式接口,由于需要参数所以get()里面输入参数,返回Person,如下。

@FunctionalInterface
public interface PersonSupply<P extends Person> {
    P get(String name, int age);
}

PersonSupply<Person> sp=Person::new;
Person person=sp.get("maplejaw",20);

PersonSupply<Person> sp=Person::new;等价于下面

PersonSupply<Person> sp=new PersonSupply<Person>{

  public Person get(String name, int age);{
      Person person=new Person(name,age);
      return person;
  }
}
  • 使用::关键字引用静态方法

    同样,写一个函数式接口,该静态方法需要参数,所以get()里传入参数,需要返回参数,所以返回String。

@FunctionalInterface
public interface PersonFactory {
    String get(String str);
}
PersonFactory pf=Person::show;
pf.show("哈哈哈");

PersonFactory pf=Person::show;等价于下面

PersonFactory pf=new PersonFactory{

  public String get(String str){
      return Person.show(str);
  }
}
  • 使用::关键字引用普通方法比较特殊。

    如果要调用的方法没有参数,可以用Class::method形式调用,但是这时需要传入一个Person实例,这时函数式接口这样写,在get()中传入Person类的实例,返回String。

@FunctionalInterface
public interface PersonFactory {
    String get(Person person);
}
 PersonSupply<Person> sp=Person::new;
 Person person=sp.get("maplejaw", 20);
 PersonFactory pf=Person::getName;
 System.out.println("--->"+sp.get(penson));

PersonFactory pf=Person::getName;等价于下面

PersonFactory pf=new PersonFactory{

  public String get(Person person){
      return person.getName();
  }
}

也可以以instance::method形式调用。这时get()不需要传参。返回String。

@FunctionalInterface
public interface PersonFactory {
    String get();
}

 PersonSupply<Person> sp=Person::new;
 Person person=sp.get("maplejaw", 20);
 PersonFactory pf=person::getName;
 System.out.println("--->"+pf.get());

PersonFactory pf=person::getName;等价于下面

Person person=new Person("maplejaw",20);
PersonFactory pf=new PersonFactory{

  public String get( ){
      return person.getName();
  }
}

如果要调用的方法有参数,必须用instance::method形式调用,这时函数式接口这样写,set传入参数。

@FunctionalInterface
public interface PersonFactory {
    void set(String name);
}

PersonSupply<Person> sp=Person::new;
Person person=sp.get("maplejaw", 20);
PersonFactory pf=person::setName;
pf.set("maplejaw");

PersonFactory pf=person::setName;等价于下面

Person person=new Person("maplejaw",20);
PersonFactory pf=new PersonFactory{

  public void set(String name){
      return person.setName(name);
  }
}

4、JAVA8 API内建的函数式接口

还记得前面提到的Supplier函数式接口吗,它就是API内建的函数式接口之一,下面将介绍一些常用的内建函数式接口。

  • Supplier

    Supplier 提供者,不接受参数,有返回值

    Supplier<Person> Supplier=new Supplier<Person>() {

            @Override
            public Person get() {
                return new Person();
            }

        };

    Supplier<Person> sp=Person::new;
  • Function 一个参数,一个返回值。常用于数据处理。
Function<String, Integer> function=new Function<String, Integer>(){

            @Override
            public Integer apply(String s) {

                return Integer.parseInt(s);
            }

        } ;
Function<String, Integer> function=Integer::parseInt;
  • Consumer 消费者,只有一个参数,没有返回值
Consumer<String> consumer=new Consumer<String>() {

            @Override
            public void accept(String t) {

            }
        };
  • Comparator 比较类
        Comparator<Integer> comparator=new Comparator<Integer>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                // TODO Auto-generated method stub
                return o1-o2;
            }

        };
  • Predicate

    Predicate 接口,抽象方法只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非):

Predicate<String> predicate=new Predicate<String>() {

            @Override
            public boolean test(String t) {

                return t.startsWith("h");
            }
        };
boolean b=predicate.test("hahaha");//判断是否符合条件
Predicate<String> predicate = String::isEmpty;
boolean b=predicate.test("hahaha");//判断是否符合条件
  • UnaryOperator 接收一个参数,返回一个参数,且参数类型相同
    UnaryOperator<String> unaryOperator=new UnaryOperator<String>() {

            @Override
            public String apply(String s) {
                // TODO Auto-generated method stub
                return s;
            }
        };
  • BinaryOperator 接收两个参数,返回一个参数,且参数类型相同
BinaryOperator<String> binaryOperator=new BinaryOperator<String>() {

            @Override
            public String apply(String t, String u) {
                // TODO Auto-generated method stub
                return t+u;
            }
        };

5、三个API

  • Optional

    Optional 这是个用来防止NullPointerException异常而引入的。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional<String> optional = Optional.of("给你一个值");
        optional.isPresent(); //判断是否为空值
        optional.get();      //获取值 ,如果空值直接抛异常。
        optional.orElse("返回空值");  //获取值 ,如果空值返回指定的值。
  • Stream(流)

    最新添加的Stream API(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

    接触过RxJava的可能对下面的代码风格比较眼熟,Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。

    怎么用Stream?Stream必须有数据源。那就给一个数据源。

    List<String> list = new ArrayList<>();
        list.add("ddd2");
        list.add("aaa2");
        list.add("bbb1");
        list.add("aaa1");
        list.add("aaa3");
        list.add("bbb3");
        list.add("ccc");
        list.add("bbb2");
        list.add("ddd1");
    • forEach list新增的for循环方法,forEach是一个最终操作(只能放在最后)

      //遍历打印数据
      list.forEach(new Consumer<String>() {
      
                  @Override
                  public void accept(String t) {
                   System.out.println("---->"+t);
      
                  }
              });

      打印结果如下

      ---->ddd2
      ---->aaa2
      ---->bbb1
      ---->aaa1
      ---->aaa3
      ---->bbb3
      ---->ccc
      ---->bbb2
      ---->ddd1
      
    • filter 过滤
      list.stream()
         .filter(new Predicate<String>() {
      
                  @Override
                  public boolean test(String t) {
      
                      return t.startsWith("a");
                  }
              })
          .forEach(new Consumer<String>() {
      
                  @Override
                  public void accept(String t) {
                   System.out.println("---->"+t);
      
                  }
              });

      打印结果如下

      ---->aaa2
      ---->aaa1
      ---->aaa3
      
    • Sort 排序
       list.stream()
              .sorted()//排序,如果不实现Comparator接口,则按默认规则排序
               .filter(new Predicate<String>() {
      
                  @Override
                  public boolean test(String t) {
      
                      return t.startsWith("a");
                  }
              })
               .forEach(new Consumer<String>() {
      
                  @Override
                  public void accept(String t) {
                   System.out.println("---->"+t);
      
                  }
              });
      
          list.stream()
               .sorted(new Comparator<String>() {
      
                  @Override
                  public int compare(String o1, String o2) {
                      // TODO Auto-generated method stub
                      return o1.compareTo(o2);
                  }
              })
               .filter(new Predicate<String>() {
      
                  @Override
                  public boolean test(String t) {
      
                      return t.startsWith("a");
                  }
              })
               .forEach(new Consumer<String>() {
      
                  @Override
                  public void accept(String t) {
                   System.out.println("---->"+t);
      
                  }
              });
    • map
      
           list.stream()
              .sorted(new Comparator<String>() {
      
                  @Override
                  public int compare(String o1, String o2) {
                      // TODO Auto-generated method stub
                      return o1.compareTo(o2);
                  }
              })
               .filter(new Predicate<String>() {
      
                  @Override
                  public boolean test(String t) {
      
                      return t.startsWith("a");
                  }
              })
               .map(new Function<String, String>() {
      
                  @Override
                  public String apply(String t) {
                      // TODO Auto-generated method stub
                      return t+"--->被我处理过了";
                  }
              })
               .forEach(new Consumer<String>() {
      
                  @Override
                  public void accept(String t) {
                   System.out.println("---->"+t);
      
                  }
              });
      
      ---->aaa1--->被我处理过了
      ---->aaa2--->被我处理过了
      ---->aaa3--->被我处理过了
    • Match 匹配,是一个最终操作
      boolean b= list.stream()
                  .anyMatch(new Predicate<String>() {
      
                      @Override
                      public boolean test(String t) {
                          // TODO Auto-generated method stub
                          return t.startsWith("a");
                      }
                  });
      
          System.out.println("----->"+b);//true
          boolean b= list.stream()
                  .allMatch(new Predicate<String>() {
      
                      @Override
                      public boolean test(String t) {
                          // TODO Auto-generated method stub
                          return t.startsWith("a");
                      }
                  });
      
          System.out.println("----->"+b);//false
    • Count 计数,是一个最终操作
      long count = list.stream()
                    .filter(new Predicate<String>() {
      
                          @Override
                          public boolean test(String t) {
      
                              return t.startsWith("a");
                          }
                      })
                    .count();
              System.out.println(count);    // 3
      
    • Reduce 规约,最终操作
           Optional<String> optional =
                      list
                          .stream()
                           .sorted()
                          .reduce(new BinaryOperator<String>() {
      
                              @Override
                              public String apply(String t, String u) {
      
                                  return t+u;
                              }
                          });
           System.out.println("---->"+optional.get());
           //---->aaa1aaa2aaa3bbb1bbb2bbb3cccddd1ddd2
    • findFirst 提取第一个,最终操作
       Optional<String> optional =
                      list
                          .stream()
                           .sorted()
                          .findFirst();
           System.out.println("---->"+optional.get()); //aaa1
      
  • parallelStream(并行流)

    并行化之后和之前的代码区别并不大。并且并行操作下,速度会比串行快。但是需要注意的是不用在并行流下排序,并行流做不到排序。

 list.parallelStream()
            .filter(new Predicate<String>() {

                @Override
                public boolean test(String t) {
                    // TODO Auto-generated method stub
                    return t.startsWith("a");
                }
            })
            .forEach(new Consumer<String>() {

                @Override
                public void accept(String t) {
                    // TODO Auto-generated method stub
                    System.out.println("--->"+t);
                }
            });

    list.parallelStream()
            .sorted()
            .forEach(new Consumer<String>() {

                @Override
                public void accept(String t) {
                    // TODO Auto-generated method stub
                    System.out.println("--->"+t);
                }
            });
            //打印出来的并没有排序

Lambda 表达式

在上面你是不是觉得::有时候挺好用的?可以不用再new接口,再也不用写烦人的匿名内部类了,比如

    Supplier<Person> sp=Person::new;

但是::的使用场景还是比较有限的。Lambda表达式的诞生就是为了解决匿名内部类中饱受诟病的问题的。

  • 什么是Lambda表达式

    Lambda表达式是Java8的一个新特性,它提供了一种更加清晰和简明的方式使用函数式接口(以前被叫作单一方法接口)。使用Lambda表达式能够更加方便和简单的使用匿名内部类,比如对于集合的遍历、比较、过滤等等。

  • Lambda表达式格式

    (type1 arg1, type2 arg2…) -> { body }

    每个lambda都包括以下三个部分:

    参数列表:(type1 arg1, type2 arg2…)

    箭头: ->

    方法体:{ body }

    方法体既可以是一个表达式,也可以是一个语句块:

    • 表达式:表达式会被执行然后返回执行结果。
    • 语句块:语句块中的语句会被依次执行,就像方法中的语句一样,return语句会把控制权交给匿名方法的调用者。

      表达式函数体适合小型lambda表达式,它消除了return关键字,使得语法更加简洁。

以下是一些例子

(int a, int b) -> {  return a + b; }
( a,  b) -> {  return a + b; }
( a,  b) -> a+b
() -> System.out.println("s")
(String s) -> { System.out.println(s); }
  • 一个 Lambda 表达式可以有零个或多个参数
  • 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同
  • 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b)
  • 空圆括号代表参数集为空。例如:()->{System.out.println(“s”);};
  • 当只有一个参数,且其类型可推导时,圆括号()可省略。
  • 如果 Lambda 表达式的主体只有一条语句,花括号{}可省略,且不能以分号结尾
  • 如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中,每条语句必须以分号结尾。

Lambda表达式可以用来简化内部类写法,比如

   //常规代码
   Runnable runable=new Runnable() {

        @Override
        public void run() {

            System.out.println("--->");
        }
    };

    //Lambda表达式
    Runnable runable=()->{System.out.println("--->");};
    //启动一个线程
    new Thread(()->{System.out.println("--->");}).start();

还记得前面介绍的Predicate接口吗?现在我们再来用Lambda表达式写一遍。

//一般写法
Predicate<String> predicate=new Predicate<String>() {

            @Override
            public boolean test(String t) {

                return t.startsWith("h");
            }

        };
//Lambda写法
Predicate<String> predicate=(String s)->{s.startsWith("h");};

你现在是不是觉得Lambda表达式太神奇了?居然可以写出这么简洁的代码。

还记得内部类使用局部变量时需要把变量声明为final吗,Lambda表达式则不需要。不过虽然不用声明final,但也不允许改变值。

        String s="sss";
        new Thread(()->{
            System.out.println(s);
        }).start();

此外,内部类引用外部类也不用使用MainActivity.this,这种操蛋的代码了。

在Lambda表达式中this,指的就是外部类,因为根本就没有内部类的概念啊。

  btn.setOnClickListener(()->{
            Toast.makeText(this,"xxx",Toast.LENGTH_SHORT).show();
        });

现在回过头来把前面Stream中的代码用Lambda表达式再写一遍。

         list.stream()
             .sorted((s1,s2)->s1.compareTo(s2))
             .filter((s)->s.startsWith("a"))
             .map((s)->s+"被我处理过了")
             .forEach(s->System.out.println(s));

代码简洁的简直让人窒息。但是能不能更简洁一点呢?当然是可以的,首先我们检查一下哪里可以替换成::关键字,然后作如下替换,是不是更简洁了。关于替换规则,请看前面的介绍。

 list.stream()
            .sorted((s1,s2)->s1.compareTo(s2))
             .filter((s)->s.startsWith("a"))
             .map((s)->s+"被我处理过了")
             .forEach(System.out::println);

打印结果如下

aaa1被我处理过了
aaa2被我处理过了
aaa3被我处理过了
  • 显示指定目标类型

    如果Lambda表达式的目标类型是可推导的,就不用指定其类型,如果Lambda表达式的参数类型是可以推导,就不用指定参数类型。因为编译器可以根据上下文自动推导出其类型,然后进行隐式转换。但是,有些场景编译器是没法推导的。比如下面这样的,如果不显示指定类型,编译器就会提示错误

//接口一
public interface IMyInterface1 {
    void opreate(String str);
}
//接口二
public interface IMyInterface2 {
    void opreate(int i);
}
//Person类
public class Person类 {
    private String name;
    private int age;

    public Test(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void opreate(IMyInterface1 inter){
        inter.opreate(name);
    }

    public void opreate(IMyInterface2 inter){
        inter.opreate(age);
    }
}

 //这样写是错误的,因为编译器无法推导出其目标类型
  new Test("maplejaw",20).opreate((name)->System.out.println(name));

解决办法有两个

一、指定参数类型,但是如果两个接口的参数类型是一样的,就只能显示指定目标类型。

  new Test("maplejaw",20).opreate((String name)->System.out.println(name));

二、指定目标类型

  new Test("maplejaw",20).opreate((IMyInterface1) (s)->System.out.println(s));
  new Test("maplejaw",20).opreate((IMyInterface1) System.out::println);

由于目标类型必须是函数式接口,所以如果想赋值给Object对象时,也必须显示转型。

Object runnable=(Runnable)()->{System.out.print("--->");};

关于Lambda表达式的介绍到此为止,想更深入了解推荐【深入理解Java 8 Lambda】这篇文章。

最后

当初学习Lambda表达式的时候,由于网上的资料比较零散,且直接用了JAVA8的新API来做演示,由于对新API不是很熟导致学习的时候走了一些弯路,看得一头雾水。所以决定把我的学习路线给记录下来,或许可以帮助部分人。

Lambda表达式是把双刃剑,让代码简洁的同时,降低了代码的可读性。但是作为程序员,追逐新技术的脚步不能停下。



本文参考了【深入理解Java 8 Lambda】【JAVA8 十大新特性详解】两篇文章

时间: 2024-10-14 20:45:39

JAVA8 Lambda表达式完全解析的相关文章

Java8 Lambda表达式深入学习(2) -- InvokeDynamic指令详解

为了更好的支持动态类型语言,Java7通过JSR292给JVM增加了一条新的字节码指令:invokedynamic.之后,JVM上面的一些动态类型语言,比如Groovy(2.0+)和JRuby(1.7.0+)都开始支持invokedynamic.不过让人意外的是,为动态语言量身定制的invokedynamic指令,居然也被用到了Java8的Lambda表达式(JSR335)实现上.本文会对invokedynamic(以下简写做indy)指令做出详细解释. 测试代码 Java7以及更早版本的Jav

Java8 Lambda表达式深入学习(4) -- Java8实现方式

前几篇文章讨论了函数式接口和Lambda表达式语法.invokedynamic指令,以及Groovy2如何利用indy指令.本篇文章在前面几篇的基础之上,简要介绍Java8底层是如何实现Lambda表达式的. 示例代码 本文将以下面的代码为例展开讨论: import java.util.Arrays; import java.util.List; public class LambdaImplTest { public static void main(String[] args) { m1(A

java8 lambda表达式初接触

环境是jdk8 代码如下: package memTest; /** * Created by PC on 2014/8/5. */ public class LambdaOne { public static void test(){ new Thread(()-> System.out.print("hi") ).start(); } public static void main(String[] args) { new LambdaOne().test(); } } ja

深入学习Java8 Lambda表达式 -- 从函数式接口说起

希望本文能够成为Java8 Lambda表达式的快速入门指南. 函数式接口 理解Functional Interface(函数式接口,以下简称FI)是学习Java8 Lambda表达式的关键所在,所以放在最开始讨论.FI的定义其实很简单:任何接口,如果只包含唯一一个抽象方法,那么它就是一个FI.为了让编译器帮助我们确保一个接口满足FI的要求(也就是说有且仅有一个抽象方法),Java8提供了@FunctionalInterface注解.举个简单的例子,Runnable接口就是一个FI,下面是它的源

Lambda表达式树解析(下)

概述 前面章节,总结了Lambda树的构建,那么怎么解析Lambda表达式树那?Lambda表达式是一种委托构造而成,如果能够清晰的解析Lambda表达式树,那么就能够理解Lambda表达式要传递的正式意图.解析Lambda表达式树意义很大,比如我们用的EF框架.Rafy框架,里面封装了大量的Lambda查询表达式,通过解析表达式转换成SQL语句,即可以查询数据库,将数据呈现给前台用户: Lambda表达式树解析 下面代码块是标识Express各个节点的信息,ExpressionType.Cal

Java8 Lambda表达式应用案例 -- 单线程游戏服务器+异步数据库操作

前段时间我们游戏服务器的开发环境升级到了Java8,这两天我又把服务器的线程模型重新设计了一下,用上了Lambda表达式.Lambda表达式确实能够大幅简化Java代码,特别是丑陋不堪的匿名内部类,这篇文章主要就是想和大家分享这一点. 线程模型 首先简单介绍一下我们游戏服务器的线程模型,大致如下图所示: Netty线程池只处理消息的收发,当Netty收到消息之后,会交给游戏逻辑线程处理.由于是单线程在处理游戏逻辑,所以每一个消息必须很快处理完,也就是说,不能有数据库等耗时操作,不然逻辑线程很可能

Java8 Lambda表达式详解手册及实例

先贩卖一下焦虑,Java8发于2014年3月18日,距离现在已经快6年了,如果你对Java8的新特性还没有应用,甚至还一无所知,那你真得关注公众号"程序新视界",好好系列的学习一下Java8的新特性.Lambda表达式已经在新框架中普通使用了,如果你对Lambda还一无所知,真得认真学习一下本篇文章了. 现在进入正题Java8的Lambda,首先看一下发音 ([?l?md?])表达式.注意该词的发音,b是不发音的,da发[d?]音. 为什么要引入Lambda表达式 简单的来说,引入La

用Java8 Stream和 Lambda表达式来解析文件的一个例子

最近我想从一个日志文件中提取出指定的数据,下面是日志的一部分: 2015-01-06 11:33:03 b.s.d.task [INFO] Emitting: eVentToRequestsBolt __ack_ack [-6722594615019711369 -1335723027906100557] 2 2015-01-06 11:33:03 c.s.p.d.PackagesProvider [INFO] ===---> Loaded package com.foo.bar 3 2015-

【Java学习笔记之三十一】详解Java8 lambda表达式

Java 8 发布日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Java 8之前,如果想将行为传入函数,仅有的选择就是匿名类,需要6行代码.而定义行为最重要的那行代码,却混在中间不够突出.Lambda表达式取代了匿名类,取消了模板,允许用函数式风格编写代码.这样有时可读性更好,表达更清晰.在Java生态系统中,函数式表达与对面向对象的全面支持是个激动人心的进步.将进一步促进并行