Java8新特性之Lambda表达式

概述

        lambda表示数学符号“λ”,计算机领域中λ表明“λ演算”,表达了计算机中最基本的概念:“调用”和“置换”。html

全局model代码:Employee.javajava

package www.muzi.com.model;

/**
 * Date:2017/3/3 12:44
 */
public class Employee {
	private String name;
	private int age;

	public Employee() {
	}

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

	public Employee(String name) {
		this.name = name;
	}

	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;
	}

	@Override
	public String toString() {
		return "Employee{" +
				"name='" + name + '\'' +
				", age=" + age +
				'}';
	}
}

Lambda表达式特色

  1.  Lambda表达式是一段能够传递的代码块,能够被执行一次或屡次。
  2. 减小编程代码量
  3. Lambda表达式能够转换为函数式接口
  4. Lambda表达式能够在闭包做用域中有效的访问final变量

Lambda表达式语法

        Java8中引入了一个新的操做符"->",该操做符称做箭头操做符或者Lambda操做符,箭头操做符将Lambda表达式拆分为两部分:编程

左侧:Lambda 表达式参数列表
右侧:Lambda 表达式中须要执行的功能,及Lambda体api

变量做用域

  1. Lambda还包括自由变量的值,这里的“自由”指的是那些不是参数而且没有在代码中定义的变量。
    public void repeatMessage(String content, int count) {
    		Runnable r = () -> {
    			for (int i = 0; i < count; i++) {
    				System.out.println(i + "-" + content);
    				count++;//错误,不能更改已捕获变量的值
    			}
    		};
    		r.run();
    	}
    
    	@Test
    	public void test8() {
    		repeatMessage("测试", 10);
    	}

     

  2. Lambda表达式的方法体与嵌套代码块有着相同的做用域。所以它也适合一样的命名冲突和屏蔽规则。在Lambda表达式中不容许声明一个与局部变量同名的参数或者局部变量。
    @Test
    	public void test9(){
    		//嵌套台代码块
    		String ss = "";
    		{
    			String ss="dd";
    		}
    		//Lambda
    		Comparator<String> com = (ss, yy) -> Integer.compare(ss.length(), yy.length());
    		System.out.println(ss);
    	}

     

语法格式一:无参数,无返回值  () -> System.out.println("Hello Lambda");数组

@Test
	public void test1(){
		int num = 0; //jdk1.7以前,必须是final的
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println("Hello World!" + num);
			}
		};
		r.run();
		System.out.println("------------------");
		Runnable r1 = () -> System.out.println("Hello Lambda!" + num);
		r1.run();
	}

语法格式二:有一个参数,无返回值  (x) -> System.out.println(x);闭包

语法格式三:当只有一个参数时,小括号能够省略不写  x -> System.out.println(x);oracle

@Test
	public void test2(){
		Consumer<String> con = (x) -> System.out.println(x);
		Consumer<String> con1 = x -> System.out.println(x);
		con.accept("测试Lambda表达式!");
	}

语法格式四:当有两个或以上参数时,有返回值,而且Lambda中有多条语句
(x, y) -> {
             System.out.println("函数式接口");
             return Integer.compare(x, y);
 };app

@Test
	public void test3(){
		Comparator<Integer> com = (x, y) -> {
			System.out.println("函数式接口");
			return Integer.compare(x, y);
		};
		System.out.println(com.compare(2, 3));
	}

语法格式五:当有两个或以上参数时,有返回值,Lambda中有一条语句,大括号和return能够省略不写dom

(x, y) -> Integer.compare(x, y);ide

@Test
	public void test4(){
		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
		System.out.println(com.compare(2, 3));
	}


语法格式六:Lambda参数列表的数据类型能够省略不写,由于JVM编译器能够经过上下文推断出,数据类型,即“类型推断”
(Integer x, Integer y) -> Integer.compare(x, y);

@Test
	public void test5(){
		Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
		System.out.println(com.compare(2, 3));
		//类型推断举例
		List<String> list = new ArrayList<>();//jdk1.7中new ArrayList<String>()必须带类型,1.8版本不须要带类型
	}

Lambda表达式须要"函数式接口"的支持

函数式接口:接口中只有一个抽象方法的接口,成为函数式接口。
可使用注解@FunctionalInterface修饰,能够检查是不是函数式接口。

函数式接口源代码:

package www.muzi.com;

/**
 * Date:2017/3/6 18:02
 */
@FunctionalInterface
public interface MyFun<T> {
	public Integer getValue(Integer num);
}
//需求:对一个数进行运算
	@Test
	public void test6(){
		Integer num = operation(100, x -> x * x);
		System.out.println("num = " + num);

		Integer num1 = operation(200, y -> y + 200);
		System.out.println("num1 = " + num1);
	}

	public Integer operation(Integer num, MyFun<Integer> mf){
		return mf.getValue(num);
	}

由于目前在写Lambda表达式时,老是须要去写一个函数式接口。这样其实也挺繁琐,其实Java8已经替咱们内置了许多函数式接口,接下来介绍Java8内置四大函数式接口。

Java8内置四大函数式接口

       在Java8中添加了许多内置的函数式接口:

        

    这里就展现如下四中函数式接口,其余函数式接口看java8文档:

http://docs.oracle.com/javase/8/docs/api/index.html

  1. Consumer<T> : 消费型接口
    //Consumer<T> : 消费型接口
    	@Test
    	public void test1(){
    		happy(10000, m -> System.out.println("订餐消费" + m + "元"));
    	}
    
    	public void happy(double money, Consumer<Double> con){
    		con.accept(money);
    	};

     

  2. Supplier<T> : 供给型接口
    //Supplier<T> : 供给型接口
    	@Test
    	public void test2(){
    		List<Integer> numList = getNumberList(10, () -> (int)(Math.random() * 100));
    		for (Integer n : numList) {
    			System.out.println(n);
    		}
    	}
    
    	//需求:产生指定个数的整数,并放到集合中
    	public List<Integer> getNumberList(int num, Supplier<Integer> sup){
    		List<Integer> list = new ArrayList<>();
    		for (int i = 0; i < num; i++) {
    			Integer n =  sup.get();
    			list.add(n);
    		}
    		return list;
    	};

     

  3. Function<T, R> : 函数型接口
    //Function<T, R> : 函数型接口
    	@Test
    	public void test3(){
    		String str = strHandler("测试函数式接口  ", x -> x.trim());
    		System.out.println(str + "--");
    	}
    
    	//需求:处理字符串
    	public String strHandler(String str, Function<String, String> fun){
    		return fun.apply(str);
    	}

     

方法引用

       方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可使用方法引用(能够将方法引用理解为 Lambda 表达式的另一种表现形式)。

      ::操做符将方法名和对象或类的名字分隔开来,主要介绍常使用的三种方法引用方式。

  1. 对象的引用 :: 实例方法名
    //对象的引用 :: 实例方法名
    	@Test
    	public void test1(){
    		Consumer<Integer> con = (x) -> System.out.println(x);
    
    		//使用方法引用实现
    		PrintStream ps = System.out;
    		Consumer<Integer> con1 = ps::println;
    
    		Consumer<Integer> con2 = System.out::println;
    		con2.accept(1234);
    	}
    
    	@Test
    	public void test2(){
    		Employee employee = new Employee("木子",23);
    		Supplier<String> sup = employee:: getName;
    		String name = sup.get();
    		System.out.println(name);
    	}

     

  2. 类名 :: 静态方法名
    //类名 :: 静态方法名
    	@Test
    	public void test3(){
    		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    
    		//方法引用
            //方法引用所引用的方法的参数列表与返回值类型,须要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
    		Comparator<Integer> com1 = Integer:: compare;
    		int result = com1.compare(3, 5);
    		System.out.println(result);
    	}

     

  3. 类名 :: 实例方法名
    //类名 :: 实例方法名
    	@Test
    	public void test4(){
    		BiPredicate<String, String> bp = (x, y) -> x.equals(y);
    		//若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
    		BiPredicate<String, String> bp1 = String:: equals;
    		boolean result = bp1.test("as", "as");
    		System.out.println(result);
    	}

    注意:
           ①方法引用所引用的方法的参数列表与返回值类型,须要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
          ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName

构造器引用

格式:  ClassName :: new  

//构造器引用
	@Test
	public void test5(){
		Supplier<Employee> sup = () -> new Employee();
		//构造器引用,自动匹配对应的构造器
		Supplier<Employee> sup1 = Employee::new;//由于没有传参数,这里的new引用的是无参构造器
		Employee employee = sup1.get();
		System.out.println(employee); //Employee{name='null', age=0}
	}

	@Test
	public void test6(){
		Function<String, Employee> fun = (x) -> new Employee(x);

		Function<String, Employee> fun1 = Employee::new;//这里引用的是一个参数的构造器
		System.out.println(fun1.apply("haha"));//Employee{name='haha', age=0}
	}

构造器引用 : 构造器的参数列表,须要与函数式接口中参数列表保持一致!

数组引用

格式: Type :: new

//数组引用
	@Test
	public void test7(){
		Function<Integer, String[]> fun = (x) -> new String[x];
		String[] strs = fun.apply(10);
		System.out.println(strs.length);  //10

		Function<Integer, String[]> fun1 = String[]::new;
		String[] strs1 = fun.apply(15);
		System.out.println(strs1.length);  //15
	}
相关文章
相关标签/搜索