Java8 Lambda 的使用指南

原文地址:https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#syntax

对于匿名内部类存在一个问题,如果接口只有一个方法,那么该接口的匿名内部类的实现将看起来很臃肿,lambda表达式将可以让你的实现更加优雅。

如果打算将一个方法作为一个参数传入另一个方法,例如对按钮的点击事件做出响应,那么lambda将帮你更容易的实现。

使用lambda的几个场景的场景.

场景1,从列表中找出符合条件的人员(年龄大于18岁的人)

public class Person {
public enum Gender{
MALE, FEMALE
}
private String name;
private Gender sex;
private Integer age;
public String getInfo(){
return toString();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
} public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
getAgeOlderThan(ps,18);
} public static void getAgeOlderThan(List<Person> ps, int age) {
for (Person p: ps) {
if(p.getAge() > age){
System.out.println(p.getInfo());
}
}
}
}

场景2,如果上面的查询条件变动,那就需要重写代码(查询条件改为,在50岁与18岁之间的人)

public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
getAgeBetween(ps,18,50);
} public static void getAgeBetween(List<Person> ps, int down,int up) {
for (Person p: ps) {
if(p.getAge() > down && p.getAge() < up){
System.out.println(p.getInfo());
}
}
}
}

场景3,可以看到上面的实现,每当出现一个新的查询条件,都需要新添加一个方法,我们想到引入接口使用多态来覆盖不同场景,引入用来做判断的接口PersonChecker和他的实现类CheckPersonWithGender。如果需要修改需求,只需要在添加一个实现类,比方说通过name来查找,只需要额外添加要给CheckPersonWithName类。

public interface CheckPerson {
boolean check(Person p);
} // 找出所有性别为指定类型的人
public class CheckPersonWithGender implements CheckPerson{
@Override
public boolean check(Person p) {
if(p.getSex().equals(Person.Gender.FEMALE)){
return true;
}
return false;
}
} // 找出所有名字为pikzas的人
public class CheckPersonWithName implements CheckPerson{
@Override
public boolean check(Person p) {
if(p.getName().equals("pikzas")){
return true;
}
return false;
}
} public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
getByFilter(ps,new CheckPersonWithGender());
getByFilter(ps,new CheckPersonWithName());
} public static void getByFilter(List<Person> ps,CheckPerson checker) {
for (Person p: ps) {
if(checker.check(p)){
System.out.println(p.getInfo());
}
}
}
}

场景4,上面的接口的引入方便了我们使用多态来扩展系统,但是每针对一个特定的过滤条件,我们都需创建一个新的接口实现类,于是可以通过匿名类的方式来将实现简化

public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
// 此处通过匿名类的方式避免了新创建一个类
getByFilter(ps,new CheckPerson(){
@Override
public boolean check(Person p) {
return p.getAge() > 50;
}
});
} public static void getByFilter(List<Person> ps,CheckPerson checker) {
for (Person p: ps) {
if(checker.check(p)){
System.out.println(p.getInfo());
}
}
}
}

场景5,可以看到上面通过内部类的方式已经使代码相当精简,但是还是有内部类的存在,于是便在Java8中推出了Lambda来替换这种只有一个方法需要实现的内部类,将代码再次简化。

public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
// 此处通过一个lambda表达式清晰明了的替换了一大堆内部类的实现
getByFilter(ps,(Person p) -> p.getAge() > 18);
} public static void getByFilter(List<Person> ps,CheckPerson checker) {
for (Person p: ps) {
if(checker.check(p)){
System.out.println(p.getInfo());
}
}
}
}

场景6,上面用(Person p) -> p.getAge() > 18 替换了匿名内部类,主要是需要对数据做逻辑判断的接口CheckPerson的实现。但是该接口在Java8中有官方给定的一个替代接口,java.util.function.Predicate<T>,于是又可以少定义一个接口。

public interface CheckPerson {
boolean check(Person p);
}
// 替换为
interface Predicate<T> {
boolean test(T t);
}
public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
//
getByFilter(ps, p -> p.getAge() > 18);
getByPreditor(ps, (Person p) -> p.getAge() < 50);
}
public static void getByFilter(List<Person> ps,CheckPerson checker) {
for (Person p: ps) {
if(checker.check(p)){
System.out.println(p.getInfo());
}
}
}
// 使用 Predicate<Person> checker 替换了 CheckPerson checker 进一步抽象,使接口变得更为通用
// 对应用来做条件判定的方法变为Predicate中的test方法
public static void getByPreditor(List<Person> ps,Predicate<Person> checker) {
for (Person p: ps) {
if(checker.test(p)){
System.out.println(p.getInfo());
}
}
}
}

场景7,上面的例子都是简单的将符合条件的对象打印了出来,同理于官方定义Predicate<T>用来对数据做过滤,Java8还提供了一个接口Consumer<T>来定义对满足条件的数据该执行的动作。

public interface Consumer<T> {
void accept(T t);
}
public class Demo {

    public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
getByFilter(ps, p -> p.getAge() > 18);
getByPreditor(ps, p -> p.getAge() < 50);
getByPreditorAndActByConsumer(
ps,
p-> p.getAge() > 18 && p.getAge() < 50, // 对Predicate接口中test方法的实现
p -> System.out.println(p.getInfo())); // 对Consumer接口中accept方法的实现
} public static void getByFilter(List<Person> ps, CheckPerson checker) {
for (Person p : ps) {
if (checker.check(p)) {
System.out.println(p.getInfo());
}
}
} public static void getByPreditor(List<Person> ps, Predicate<Person> checker) {
for (Person p : ps) {
if (checker.test(p)) {
System.out.println(p.getInfo());
}
}
} // 对符合条件的数据应用动态的处理方式
public static void getByPreditorAndActByConsumer(List<Person> ps, Predicate<Person> checker, Consumer<Person> consumer) {
for (Person p : ps) {
if (checker.test(p)) {
consumer.accept(p);
}
}
} }

场景8,如果对于满足条件的数据需要额外的处理,然后再交给Consumer方法来执行动作,Java8提供了,例如我需要将每个人男性的年龄都加10,然后打印出来。

public interface Function<T, R> {
R apply(T t);
}
public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>(); ps.add(new Person("alex",Person.Gender.MALE,24));
ps.add(new Person("Blex",Person.Gender.MALE,29));
getByPreditorAndActByConsumerAndHandleWithFunction(
ps,
p-> p.getAge() > 18 && p.getAge() < 50, // 对Predicate接口中test方法的实现
p -> p.getAge() + 10 ,
p -> System.out.println(p)); // 对Consumer接口中accept方法的实现
} // 对符合条件的数据应用动态的处理方式
public static void getByPreditorAndActByConsumerAndHandleWithFunction(List<Person> ps, Predicate<Person> checker, Function<Person,Integer> function, Consumer<Integer> consumer) {
for (Person p : ps) {
if (checker.test(p)) {
Integer ret = function.apply(p);
consumer.accept(ret);
}
}
}
}

lambda的格式

从前面已经可以看到 lanmda主要由三部分构成 形参部分表达式 -> 逻辑代码表达

形参部分表达式的标准写法是(ParamA a,ParamB b,....),参数类型可以省略,如果入参个数只有一个,那么小括号也能省略。

public class Demo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<Person>();
getByPreditorAndActByConsumerAndHandleWithFunction(
ps,
p -> p.getAge() > 18 && p.getAge() < 50, // 单个参数,直接写形参
(Person p) -> p.getAge() + 10 , // 单个参数,用括号包围起来,写上参数类型
(p) -> System.out.println(p)); // 单个参数,用括号包围起来,不写上参数类型
} // 对符合条件的数据应用动态的处理方式
public static void getByPreditorAndActByConsumerAndHandleWithFunction(List<Person> ps, Predicate<Person> checker, Function<Person,Integer> function, Consumer<Integer> consumer) {
for (Person p : ps) {
if (checker.test(p)) {
Integer ret = function.apply(p);
consumer.accept(ret);
}
}
}
} public class MultiParam {
public interface MathMethod{
int operation(int a, int b);
} public int doRun(int a, int b, MathMethod method){
return method.operation(a,b);
} public static void main(String[] args) {
MathMethod addOp = (int a,int b) -> a+b; // 入参用括号围起来,标明入参数据类型
MathMethod subOp = (a,b) -> a-b; // 入参用括号围起来,不标数据类型
MultiParam demo = new MultiParam();
System.out.print("23 + 55 = ");
System.out.print(demo.doRun(23,55,addOp));
System.out.println();
System.out.print("55 + 22 = ");
System.out.print(demo.doRun(55,22,subOp));
}
}

逻辑代码表达的标准写法为{return expression},在实现的接口方法不是void的情况下,可以同时将花括号和return省略,如果接口方法是void返回。则不能写return。

public class MultiParam {
public interface MathMethod{
int operation(int a, int b); // 接口内方法不是void
} public int doRun(int a, int b, MathMethod method){
return method.operation(a,b);
} public static void main(String[] args) {
MathMethod addOp = (int a,int b) -> {return a+b;}; // 这时是一个标准写法,应为接口方法不是void,所以return必须存在。
MathMethod subOp = (a,b) -> a-b; // {}和return可以同时去掉
MultiParam demo = new MultiParam();
System.out.print("23 + 55 = ");
System.out.print(demo.doRun(23,55,addOp));
System.out.println();
System.out.print("55 + 22 = ");
System.out.print(demo.doRun(55,22,subOp));
}
//之前的Consumer里面的accept方法返回值为void 就可以通过如下方式来写
(p) -> {System.out.println(p)}; // 带上花括号,但是括号里面不能有return,因为这是lambda实现的接口方法返回的void。
(p) -> System.out.println(p); // 省略花括号,同理return 也不能存在。

Java8 Lambda使用指南的更多相关文章

  1. java8 Lambda表达式的新手上车指南(1)

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

  2. java8 Lambda表达式的新手上车指南(1)--基础语法和函数式接口

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

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

    Java 8 发布日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Java 8之前 ...

  4. java8 快速入门 lambda表达式 Java8 lambda表达式10个示例

    本文由 ImportNew - lemeilleur 翻译自 javarevisited.欢迎加入翻译小组.转载请见文末要求. Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发 ...

  5. JAVA8 Lambda初体验

    import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.u ...

  6. Java8 lambda表达式10个示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...

  7. java8 Lambda表达式的10个例子(转)

    原文:http://jobar.iteye.com/blog/2023477 Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 Java代码 收藏代码// ...

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

    先贩卖一下焦虑,Java8发于2014年3月18日,距离现在已经快6年了,如果你对Java8的新特性还没有应用,甚至还一无所知,那你真得关注公众号"程序新视界",好好系列的学习一下 ...

  9. Java8 lambda表达式10个示例<转>

    例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...

随机推荐

  1. I+Me=完整的自我

    这是这个系列的第二篇文章,如同第一篇一样,这篇文章会在24小时后删除. 之所以如此极端,因为我自认为这篇文章很有价值,不以这种方式,大家即使看了,也只会一带而过,不会真的汲取到营养. 这篇文章涉及的关 ...

  2. JavaScript中四种不同的属性检测方式比较

    JavaScript中四种不同的属性检测方式比较 1. 用in方法 var o = {x:1}; "x" in o; //true "y" in o; //fa ...

  3. opencv 实现人脸检测(harr特征)

    我这里用的是已经训练好的haar级联分类器. 眼睛检测 haarcascade_eye_tree_eyeglasses.xml 人脸检测 haarcascade_frontalface_alt2.xm ...

  4. Redis事务实现原理

    一:简介 Redis事务通常会使用MULTI,EXEC,WATCH等命令来完成,redis实现事务实现的机制与常见的关系型数据库有很大的却别,比如redis的事务不支持回滚,事务执行时会阻塞其它客户端 ...

  5. Codeforces Round #621 (Div. 1 + Div. 2)E(二分查找,枚举分界点,容斥原理)

    可以把每头牛看作一个位置,有几对牛可以放置相当于有几对位置可以给它睡觉,没有牛可以在其他牛的位置睡觉,所以有几对牛放置的可能答案就乘多少(相当于在原本的两个集合里分别插入一个元素,元素代表它睡觉的位置 ...

  6. 解决 genymotion 安装apk报错 app contains ARM native code and your Genymotion device cannot run ARM instructions

    1.某些APP安装在模拟器时提示“ this probably means that the app contains ARM native code and your Genymotion devi ...

  7. python之路之html

    def index(request): print request.POST print request.GET print request.FILES for item in request.FIL ...

  8. AcWing 793. 高精度乘法

    https://www.acwing.com/problem/content/795/ #include<bits/stdc++.h> using namespace std; //A*b ...

  9. bzoj 2049: [Sdoi]Cave 洞穴探测 (LCT)

    第一次写lct (这是一道lct裸题 这次没有可爱(划掉)的同学教我,虽然有模板,但是配合网上的讲解还是看不懂QAQ 然后做了几道题之后总算有些感觉辣 于是决定给自己挖个坑,近期写一个lct详解(不过 ...

  10. Flink 应用的一致性保障

    应用一致性保障 在Flink中,会自动做检查点,用于故障时恢复一个应用.在恢复时,application的state信息可以根据最近完成的检查点进行重建,并继续运行.不过,仅将一个applicatio ...