java8新特性——函数式编程(lambda表达式)


前言

java是面向对象语言,但是有时候为了更加方面的实现某些功能,引入了函数式编程,具体可见本文2.2中的例子。
本文首先介绍了函数式编程中必不可少的函数式接口,之后介绍了lambda表达式的基本格式、优点,以及常见的4个函数式接口。


1.函数式接口

  • 有且仅有一个抽象方法的接口

格式:

修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}

举例:
注解:@FunctionalInterface

@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}

2.函数式编程

函数式编程中的函数指的不是程序中的函数(方法),而是数学中的函数即映射关系,如:y=sin(x),描述数据(函数)之间的映射,同时需要保证相同的输入始终能得到相同的输出。

函数式编程不会保留计算中间的结果,因此也可以说是无状态的。函数式编程可以将一个函数的执行结果再交由另一个函数去处理。

Java8通过Lambda表达式与方法引用等,实现函数式编程,可将其可定义为一种简洁、可传递的匿名函数

2.1 Lambda表达式标准格式

  • 两种格式:
(parameters) -> expression

(parameters) ->{ statements; }
  • parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数,多个参数逗号隔开
  • ->:可以理解为被用于
  • 方法体:
  • List item
    • 表达式,如果只有一句的话当前表达式即为返回值,不需要写return
    • 代码:用{}括起来,如有返回值需要return
      举例:
// 返回给定字符串的长度(隐含return语句) 
(String str) -> str.length()

// 始终返回233的无参方法(隐含return语句) 
() -> 233

// 返回当前用户是否年龄大于20岁,返回一个boolean值(隐含return语句) 
(User user) -> user.getAge() > 20

// 包含多行表达式,需用花括号括起来,并使用return关键字返回
(int x, int y) -> { 
    int z = x * y; 
    return x + z; 
}

2.2 Lambda表达式举例

我们此处以通过Runnable接口实现类的创建线程为例,由于Runnable接口只有一个run()方法,所以这里从之前的直观写法到lambda表达式进行代码演示。

  1. 通过创建一个Runnable接口实现类来实现
public class TestThread {
    @Test
    public void testThread1(){
        Thread thread = new Thread(new MyRunnable(), "thread1");
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程" + i);
        }
    }

}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread() + "正在执行:" + i);
        }
    }
}
  1. 通过匿名内部类
    @Test
    public void testThread2(){
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread() + "正在执行:" + i);
                }
            }
        }, "thread1");
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程" + i);
        }

    }
  1. lambda表达式
    @Test
    public void testThread3(){
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread() + "正在执行:" + i);
            }
        }, "thread1");
        thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程" + i);
        }

    }

2.3 函数式编程的好处

  1. 减少业务逻辑和代码的分歧。他允许我们在更高层次更自然的描述业务逻辑。让代码直接描述“你想做什么”,而不是“你想怎样去做”。
  2. 延迟执行:以lambda表达式为例,通过下面的例子可以看出lambda表达式是现将代码逻辑传送进去,符合逻辑才执行,此时传进去的flag为2,不符合逻辑,则lambda中的逻辑均不执行
public class TestThread {

    @Test
    public void testDelay(){
        printLog(2, () -> {
            System.out.println("lambda执行");
            return "a" + "b" + "c";
        });

    }

    private void printLog(int flag, MessageBuilder message){
        if(flag == 1){
            System.out.println(message.buildMessage());
        }
    }
    
}

interface MessageBuilder {
    String buildMessage();
}

2.4 常用函数式接口

  • 对于各个常用接口,这里仅介绍他们的抽象方法,对于Consumer等还有一些默认方法。
  • 这四个接口,会通过后面的文章具体解析编程时的应用。

1. Supplier

对外提供”一个符合泛型类型的对象
数据。

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

举例:

import java.util.function.Supplier;
public class Demo08Supplier {
    private static String getString(Supplier<String> function) {
        return function.get();
    } public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        System.out.println(getString(()> msgA + msgB));
    }
}

2.Consumer

正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
import java.util.function.Consumer;
public class Demo09Consumer {
    private static void consumeString(Consumer<String> function) {
        function.accept("Hello");
    } public static void main(String[] args) {
        consumeString(s ‐> System.out.println(s));
    }
}

3.Predicate

对某种类型的数据进行判断,从而得到一个boolean值结果。

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
import java.util.function.Predicate;
public class Demo15PredicateTest {
    private static void method(Predicate<String> predicate) {
        boolean veryLong = predicate.test("HelloWorld");
        System.out.println("字符串很长吗:" + veryLong);
    } public static void main(String[] args) {
        method(s ‐> s.length() > 5);
    }
}

4.Function

用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
import java.util.function.Function;
public class Demo11FunctionApply {
    private static void method(Function<String, Integer> function) {
        int num = function.apply("10");
        System.out.println(num + 20);
    } public static void main(String[] args) {
        method(s ‐> Integer.parseInt(s));
    }
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力改掉拖延症的小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值