zoukankan      html  css  js  c++  java
  • Java中的Lambda表达式简介及应用

    在接触Lambda表达式、了解其作用之前,首先来看一下,不用Lambda的时候我们是怎么来做事情的。

    我们的需求是,创建一个动物(Animal)的列表,里面有动物的物种名,以及这种动物是否会跳,是否会游泳,并可以根据需要打印出会跳和会游泳的动物名。

    首先我们创建一个Animal类:

    public class Animal {
    	private String species;
    	private boolean canHop;
    	private boolean canSwim;
    	private boolean canFly;
    	
    	public Animal(String speciesName, boolean hopper, boolean swimmer, boolean flyer) {
    		species = speciesName;
    		canHop = hopper;
    		canSwim = swimmer;
    		canFly = flyer;
    	}
    	
    	public boolean canHop() {
    		return canHop;
    	}
    	
    	public boolean canSwim() {
    		return canSwim;
    	}
    
    	public boolean canFly() {
    		return canFly;
    	}
    	
    	public String toString() {
    		return species;
    	}
    }
    

    这个Animal类有四个私有的实例变量和三个共公有的方法。

    变量
    字符串型的species,用来记录动物的物种名,布尔型的canHopcanSwimcanFly,用来记录这种动物是否能跳,是否能游泳,是否会飞。
    构造方法实例化对象的时候会给这些变量赋值。

    方法
    前三个是返回值为布尔型的canHop()canSwim()canFly(),调用方法时返回canHopcanSwimcanFly变量的值
    另外还有一个重写的toString()方法,用于在程序中识别动物的物种名。

    下面这段代码创建了一个ArrayList并向List内添加了五个Animal对象,对应五种动物和各自的能力:

    List<Animal> animals = new ArrayList<Animal>();
    animals.add(new Animal("fish", false, true, false));
    animals.add(new Animal("kangroo", true, false, false));
    animals.add(new Animal("rabbit", true, false, false));
    animals.add(new Animal("turtle", false, true, false));
    animals.add(new Animal("bird", true, true, true));
    

    为了判断某种动物是否会跳跃或者会游泳(会不会飞先不管),我们可以写两个方法来返回Animal类的canHop()canSwim(),即获取到了canHopcanSwim私有变量:

    public boolean checkIfHopper(Animal a) {
    	return a.canHop();
    }
    
    public boolean checkIfSwimmer(Animal a) {
    	return a.canSwim();
    }
    

    在此为了说明Lambda表达式的作用,在这里我们把这两个方法分别放到两个类中,并把方法名改为test
    不要问为什么起名叫test而不是Test或者TEST,也不要问为什么一定要把两个方法拆分到两个类里面,照做就是了,后面会说

    public class CheckIfHopper {
    	public boolean test(Animal a) {
    		return a.canHop();
    	}
    }
    
    public class CheckIfSwimmer {
    	public boolean test(Animal a) {
    		return a.canSwim();
    	}
    }
    

    一个java文件里只能有一个public class,这里是为了方便所以把多个public class放在一段代码里的,下同

    为了校验这两种能力,我们分别创建了一个类,里面分别只有一个方法。即一个类校验一种能力。
    按照这个思路,我们可以创建一个名为CheckTraits的接口,来让上面这些类来实现这个接口:

    public interface CheckTraits {
    	boolean test(Animal a);
    }
    
    public class CheckIfHopper implements CheckTraits {
    	public boolean test(Animal a) {
    		return a.canHop();
    	}
    }
    
    public class CheckIfSwimmer implements CheckTraits {
    	public boolean test(Animal a) {
    		return a.canSwim();
    	}
    }
    

    CheckTraits接口有且只有一个方法boolean test(Animal a)。该方法接受一个Animal类型的对象,并返回布尔值。

    有了校验能力的方法,接下来我们只需要去按需要调用这些方法就好了。我们来写一个print方法,接受一个动物列表animals和一个校验种类checker作为参数,打印出列表内符合要求的动物:

    private static void print(List<Animal> animals, CheckTraits checker) {
    	for (Animal animal : animals) {
    		if (checker.test(animal)) {
    			System.out.print(animal + " ");
    		}
    		System.out.println();
    	}
    }
    

    完整的TraditionalSearch.java代码如下:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Predicate;
    
    public class TraditionalSearch {
    	public static void main(String[] args) {
    		List<Animal> animals = new ArrayList<Animal>();
    		animals.add(new Animal("fish", false, true, false));
    		animals.add(new Animal("kangroo", true, false, false));
    		animals.add(new Animal("rabbit", true, false, false));
    		animals.add(new Animal("turtle", false, true, false));
    		animals.add(new Animal("bird", true, true, true));
    
    		print(animals, new CheckIfHopper());
                    System.out.println("-----");
                    print(animals, new CheckIfSwimmer());
    	}
    
    	private static void print(List<Animal> animals, CheckTraits checker) {
    		for (Animal animal : animals) {
    			if (checker.test(animal)) {
    				System.out.print(animal + " ");
    			}
    			System.out.println();
    		}
    	}
    }
    

    代码输出结果为:

    
    kangroo 
    rabbit 
    
    bird 
    -----
    fish 
    
    
    turtle 
    bird 
      
    

    到目前为止,我们

    • 创建了一个Animal类
    • 写了两个校验方法,分别放到了两个类CheckIfHopper、CheckIfSwimmer里面
    • 写了一个接口CheckTraits,让上面的这两个类实现自这个接口
    • 在print方法里调用print(animals, new CheckIfHopper())print(animals, new CheckIfSwimmer())

    做了这么多铺垫,所以Lambda表达式到底是什么?

    首先思考一个问题,根据上面判断跳和游泳的思路,如果想增加一个是否能飞的判断,需要做什么?

    • 创建一个CheckIfFlyer类
    • 实现CheckTraits接口
    • 设置test()方法返回值为a.canFly(还记得这个test方法吗?这个就是我们校验能力的接口里唯一的一个方法名)
    • 在print方法里调用print(animals, new CheckIfFlyer())

    虽然这样做也不会增加几行代码,也就是多创建一个类的事情。但是Lambda表达式可以做到更简单:

    • 在print方法里调用print(ainmals, a -> a.canFly())或者print(ainmals, (Animal a) -> {return a.canFly();))

    看到了吗?就是这样,并不需要创建一个新的类,也不需要修改test()方法。

    我们来看一下Lambda表达式的结构:

    • 左边的a是Lambda表达式的唯一参数
    • 中间的箭头->用来分隔参数主体
    • 右边的a.canHop()主体,调用唯一方法并返回方法的返回值

    上图的结构式Lambda表达式的简洁形式,另外一种更为全面和复杂(并不):

    • 当且仅当有且只有一个参数的时候,括号和参数类型才可以被省略
    • 主体部分只有一条语句的时候,Lambda表达式不但可以让你省掉花括号{ },还可以让你省略掉return和后面的分号;
    • 主体部分有多条语句构成一个语句块的时候,花括号内分号不可省略

    现在我们了解了Lambda的形式,那么Lambda具体是怎么发挥作用的呢?这要从我们的print()方法说起:

    private static void print(List<Animal> animals, CheckTraits checker)
    

    当我们调用print(ainmals, a -> a.canFly()的时候,我们是将Lambda表达式a -> a.canFly()作为print方法的第二个参数传过去的。
    print方法的第二个参数接收类型为CheckTraits的变量,所以Java会尝试将Lambda表达式映射到CheckTraits接口上:

    boolean test(Animal a);
    
    • 因为test方法接收Animal类型的变量,所以Lambda表达式的参数也必须为Animal类型
    • 因为test方法的返回值是布尔型,所以Lambda主体也会返回布尔型的值

    所以这里其实可以理解为,把简略形式的a -> a.canFly()映射为了具体形式的(Animal a) -> {return a.canFly();}
    这里用到了一种叫延迟执行(Deferred Execution)的概念,所谓延迟执行就是”先定义,再执行“。在调用的时候定义了参数的类型和返回值,等执行到print方法里的时候再去执行主体获得返回值。

    关于Lambda还有很多更复杂的应用,比如可以使用Predicate<T>接口来省掉自己写接口的步骤,感兴趣可以进一步详细学习。
    参考资料:OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide

  • 相关阅读:
    PLSQL设置中文
    新建oracle实例
    eclipse中导入项目后中文成乱码解决办法
    安装oracle
    配置java环境变量
    学习springMVC实例1——配置和跳转到HelloWorld
    突破变态限制快捷方式提权法
    对象的内存布局
    XMl转Map-map调用公共模板
    对象的创建
  • 原文地址:https://www.cnblogs.com/limuyuan/p/java-lambda-in-oca.html
Copyright © 2011-2022 走看看