Java8之Lambda函数式编程(一)

Java8中,最重要且最实用的莫过于Lambda表达式和Stream流式编程了。它改变了以往传统的编程方式,更高效、更简洁、并且代码更具有可读性。现在基本所有的大型互联网公司很早就摒弃JDK.1.7而使用JDK1.8了,但一些传统公司依然是使用1.7版本,它们并不愿意改变。原因有二:学习成本、维护成本。但是一旦你接触它之后,你就会爱上它,因为它实在是太棒了!所以我还是强烈推荐学习并使用Java8。我本人初次学习Java8时也是在传统公司,反反复复学了好几遍(很笨),每次都有不同的感悟,后来跳槽后,发现公司已经很早就已经全面使用Java8,故而我又学习了一遍Java8。只学不用很快就会忘了,最重要的还是在工作当中多多实践吧。

  • 小李子①:筛选年龄大于18岁的童鞋

你可能会这样写:

public static List<Student> filterStudent(List<Student> list){
    List<Student> result = new ArrayList<>();
    for(Student stu : list){
        if(18 < stu.getAge()){//筛选年龄大于18
            result.add(stu);
        }
    }
    return result;
}

但是接下来,我想筛选年龄大于20岁的呢?你可能会复制粘贴上边的代码,然后将逻辑修改一下

if( 20 < stu.getAge() )    result.add(stu);

又或者是筛选男女同学、班级、教师等等...很明显这样的做法是不够灵活的。那如果使用Java8中的Lambda实现呢?

list.stream().filter(stu -> stu.getAge() > 18)
    .filter(stu -> stu.getSex() == 0)
    .filter(stu -> stu.getClasses().equals("三年一班"))

//等同于
list.stream().filter(stu -> stu.getAge()>18 && stu.getSex()==0 && stu.getClasses().equals("三年一班"))

上面这段代码,它足够灵活,你可以随意的筛选元素。并且它可读性更好,看见这段代码就能猜到他是干嘛的:筛选年龄大于18岁,性别是男,并且在三年一班的学生。

注:list是学生列表;stream()是java8中的方法,用于将集合变成流。下文会介绍。

  • 小李子②:Java中的传统线程代码
Thread t = new Thread(new Runnable(){
    @override
    public void run(){
        System.out.println("Hello Lambda!");
    }
});

在Lambda表达式中它的样子,它非常的简洁

Thread t = new Thread(() -> System.out.println("Hello Lambda!"));
  • 小李子③:

Java 8 中常用的函数式接口

函数式接口描述符原始类型特化使用场景
Predicate<T>T->booleanIntPredicate,LongPredicate, DoublePredicate涉及到类型T的布尔表达式时使用此函数式接口
Consumer<T>T->voidIntConsumer,LongConsumer, DoubleConsumer

定义了一个accept的抽象方法,用于接收T对象,并且没有返回值。

如果你需要访问T对象,并且对其【执行某些操作】,即可使用此函数式接口。

Function<T,R>T->R

IntFunction<R>,  IntToDoubleFunction, IntToLongFunction                  LongFunction<R>, LongToDoubleFunction, LongToIntFunction,
DoubleFunction<R>,

ToIntFunction<T>, ToDoubleFunction<T>, ToLongFunction<T>

接收T对象,返回R对象
Supplier<T>()->TBooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier返回T对象(常用于创建对象)
UnaryOperator<T>T->TIntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator输出一个与入参一样的值
BinaryOperator<T>(T,T)->TIntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator同类型运算
BiPredicate<L,R>(L,R)->boolean
BiConsumer<T,U>(T,U)->voidObjIntConsumer<T>,     ObjLongConsumer<T>, ObjDoubleConsumer<T>
BiFunction<T,U,R>(T,U)->R

ToIntBiFunction<T,U>, ToLongBiFunction<T,U>,

ToDoubleBiFunction<T,U>

接收T,U类型参数,返回R类型对象

Lambda实践

准备工作

public class LambdaDemo {
    private static List<Apple> appleList;
    
    /**
     *静态代码块:初始化静态变量appleList
     **/
    static {
        appleList = Arrays.asList(
                new Apple("red", 500),
                new Apple("blue", 20),
                new Apple("red", 30),
                new Apple("yellow", 20));
    }
    
    public static void main(String[] args){}
}

public class Apple {
    private String color;
    private int height;
}

public class LambdaUtils {

    /**
     * 筛选集合
     * @param list  集合
     * @param predicate boolean条件
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(List<T> list, Predicate<T> predicate){
        List<T> result = new ArrayList<>();
        for(T t : list){
            if(predicate.test(t)){
                result.add(t);
            }
        }
        return result;
    }

    /**
     * 输出集合元素
     * @param str
     * @param list
     * @param <T>
     */
    public static<T> void out(String str, List<T> list){
        System.out.println(str + " ========START========");

        for(T t : list){
            System.out.println(t);
        }

        System.out.println(str + " =========END=========");
    }

    /**
     * 改变集合中元素
     * @param list
     * @param consumer
     * @param <T>
     */
    public static <T> List<T> consumer(List<T> list, Consumer<T> consumer){
        for(T t : list){
            consumer.accept(t);
        }
        return list;
    }

    /**
     * Function<T, R>:由 T 对象转 R 对象
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> function(List<T> list, Function<T, R> function){
        List<R> result = new ArrayList<>();
        for(T t : list){
            result.add(function.apply(t));
        }
        return result;
    }

1、筛选红苹果

LambdaUtils.filter(appleList, apple -> "red".equals(apple.getColor()))

2、筛选红苹果且重量大于50的苹果

LambdaUtils.filter(appleList, 
    apple -> "red".equals(apple.getColor()) && apple.getHeight() > 50)

3、改变苹果重量

LambdaUtils.consumer(appleList, apple -> apple.setHeight(50))

4、获取苹果重量的集合

//int -> Integer 装箱操作
List<Integer> integerFunction = LambdaUtils.function(appleList, 
    apple -> apple.getHeight());

注:装箱操作在性能上是要付出代价的。装箱后的值本质上就是把原始类型包裹起来,并保存在JVM堆中。因此,装箱后的值需要更多的内存进行存储。

如何解决? 避免装箱就可以了,并且Function已经为我们提供了基本类型的函数式接口

//举个栗子
//装箱
Predicate<Integer> p = i -> i>0;
//避免装箱
IntPredicate intP = i -> i>0;
//p.test(-1);
//intP.test(-1);

方法引用

1、根据苹果的颜色进行排序

appleList.sort((Apple o1, Apple o2) -> o1.getColor().compareToIgnoreCase(o2.getColor()));
//Java编译器可以根据Lambda出现的上下文来推断Lambda表达式参数的类型
appleList.sort((o1, o2) -> o1.getColor().compareToIgnoreCase(o2.getColor()));

使用方法引用

//使用方法引用
List<String> collect = appleList.stream()
    .map(apple -> apple.getColor()).collect(Collectors.toList());
collect.sort(String::compareToIgnoreCase);

2、另一种实现方式:Comparator

//Lambda
appleList.sort(Comparator.comparing(apple -> apple.getColor()));
//方法引用
appleList.sort(Comparator.comparing(Apple::getColor));

3、构造函数引用

Supplier<Apple> appleNew = () ->  new Apple("yellow", 250);//创建一个apple对象
Apple apple = appleNew.get();
//使用方法引用与Lambda比较
Supplier<Apple> appleSupplier = Apple::new;
BiFunction<String, Integer, Apple> biFunction = Apple::new;
BiFunction<String, Integer, Apple> biLambda = (color, height) -> new Apple(color, height);
Apple green = biFunction.apply("green", 666);
Apple green_lambda = biLambda.apply("green", 777);

复合Lambda表达式

1、比较器复合

苹果重量排序,逆序排序

appleList.sort(Comparator.comparing(Apple::getHeight).reversed());

按照重量进行排序,当两个苹果重量一样时,按照颜色进行排序

appleList.sort(Comparator.comparing(Apple::getHeight).thenComparing(Apple::getColor));

2、谓词复合

negate:非

and:和

or:或

Apple apple = new Apple("yellow", 100);
Predicate<Apple> predicate = a -> a.getHeight()>120;//苹果重量大于120的函数式表达式
predicate.test(apple);//false
predicate.negate().test(apple);//true

//在重量小于120的同时,再加上绿色的筛选条件
predicate.negate().and(a -> "yellow".equals(a.getColor())).test(apple);//true
predicate.or(a -> "yellow".equals(a.getColor())).test(apple);//true

3、函数复合

andThen():X.andThen(Y),先执行x,再执行y

compose():X.compose(Y),先执行Y,再执行X

//先加1,再乘以2
Function<Integer, Integer> add = x -> x + 1;
Function<Integer, Integer> multiply = x -> x * 2;
Function<Integer, Integer> andThen = add.andThen(multiply);
Integer result = andThen.apply(2);
System.out.println("【andThen】 x + 1 => x * 2 = " + result);

//先 * 2 再 + 1
Function<Integer, Integer> compose = add.compose(multiply);
System.out.println("【compose】 x * 2 => x + 1 = " + compose.apply(2));

//总结:andThen [先] 执行调用者。 compose [后] 执行调用者

参考:《Java 8 实战》

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛声依旧叭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值