java8之lambda表达式(1)-基本语法
lambda表达式,即带有参数的表达式,为更清晰地理解lambda表达式,先看如下例子:
(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); }
(1)中代码调用Collections.sort方法对集合进行排序,其中第二个参数是一个类,准确地说是一个匿名内部类,sort方法调用内部类中的compare方法对list进行位置交换,因为java中的参数类型只能是类或者基本数据类型,所以虽然传入的是一个Comparator类,但是实际上需要传递的仅仅是compare方法,lambda表达式专门针对只有一个方法的接口(即函数式接口),Comparator就是一个函数式接口
@FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); }
@FunctionalInterface的作用就是标识一个接口为函数式接口,此时Comparator里只能有一个抽象方法。
使用lambda表达式之后(1)中的代码改造如下
(2)
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. ambda表达式的基本格式为(x1,x2)->{表达式...};
2. 在上式中,lambda表达式带有两个参数,因此两边的括号不能省略,而参数类型可以省略
3. 如果表达式只有一行,那么表达式两边的花括号可以省略
另外一个常见的例子是新建一个线程,不使用lambda表达式的写法为
(3)
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表达式的写法为
(4)
public void testThread_(){ new Thread(()-> System.out.println("hello, i am thread!")).start(); }
对于没有参数的情况 ,语法:
1.参数的括号不能省略,如果只有一句的表达式则可省略花括号和语句结尾的分号
我们构造一个只有一个参数的函数式接口
@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.参数的括号可以省略
在这里我们为了演示只有一个参数的情况自己创建了一个函数式接口,其实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"); }