Java语言09之函数式编程

1 Lambda表达式

1.1 Lambda表达式

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。可以把一个Lambda表达式看成一个接口的实现类(更准确的说是一个函数式接口的实现类,函数式接口是一个只拥有一个抽象方法的接口)。因为一个函数式接口的实现类用很多冗余代码,使用Lambda表达式可以简化代码,而只保留核心的代码。

1.2 组成部分

  • 形参列表:允许省略形参类型,如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略。
  • 箭头(->):必须通过英文中画线和大于符号组成。
  • 代码块:
    • 如果代码块只包含一条语句,可以省略代码块的花括号;
    • 如果只有一条return语句,可以省略return关键字;
    • 如果表达式需要返回值,而它的代码块中仅有一条省略了return的语句,Lambda表达式会自动返回这条语句的值。

2 函数式接口

2.1 函数式接口

函数式接口指的是有且仅有一个抽象方法的接口。

因为在JDK 8中新增了Lambda表达式,所使用的接口必须只能有一个抽象方法。所以,函数式接口就是专为Lambda而产生的特殊接口。要定义一个函数式接口,那么该接口只能有一个抽象方法。为了确保只有一个抽象方法,同时也可以告诉别人这是一个抽象方法,我们通常在接口上添加一个注解:@FunctionalInterface。

2.2 JDK内置函数式接口

  • Supplier接口:Supplier接口是java.util.function包下的一个函数式接口,该接口的抽象方法是一个无参的方法:T get(),用来获取一个泛型参数指定类型的对象数据。
  • Consumer接口:Consumer接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。它提供了一个抽象方法:void accept(T t),作用是使用一个指定泛型的数据。
  • Predicate接口:Predicate接口用来对某种类型的数据进行判断,该接口包含一个抽象方法:boolean test(T t)。此外,Predicate接口还提供了三个默认方法,and()、or()、negate()
  • Function接口:Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。Function接口提供的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。

2.2.1 Supplier接口

public class TestSupplier1 {
    public static void main(String[] args) {
        Supplier<String> supplier = getUuidProvider(8);
        System.out.println(supplier.get());
        System.out.println(supplier.get());
        System.out.println(supplier.get());
    }

    public static Supplier<String> getUuidProvider(int length) {
        return new Supplier<String>() {
            @Override
            public String get() {
                String uuid = UUID.randomUUID().toString();
                return uuid.substring(0, length);
            }
        };
    }
}

2.2.2 Consumer接口

public class TestConsumer {

    public static void main(String[] args) {
        Consumer<List<Integer>> calculator = getMax();
        calculator.accept(Arrays.asList(1, 2, 3));
    }

    public static Consumer<List<Integer>> getMax() {
        return new Consumer<List<Integer>>() {
            @Override
            public void accept(List<Integer> integers) {
                System.out.println(Collections.max(integers));
            }
        };
    }
}

2.2.3 Predicate接口

public class TestPredicate {
    public static void main(String[] args) {
        Predicate<String> predicate = getLongNamePredicate();
        List<String> names = Arrays.asList("1", "22", "333");
        names.stream().filter(predicate)
                .forEach(System.out::println);
    }

    public static Predicate<String> getLongNamePredicate() {
        return new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() > 2;
            }
        };
    }
}

2.2.4 Function接口

public class TestFunction {
    public static void main(String[] args) {
        Function<Integer, String> transformer = getTransformer(1);
        String target = transformer.apply(1234);
        System.out.println(target);
    }

    public static <T> Function<T, String> getTransformer(T source) {
        return new Function<T, String>() {
            @Override
            public String apply(T t) {
                if (source instanceof Integer) {
                    return String.valueOf(t);
                }
                return null;
            }
        };
    }
}

3 方法引用

当要传递给Lambda表达式的方法体已经有实现了,便可以使用方法引用。方法引用可以看做是Lambda表达式的更深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。

  • 静态方法的方法引用
  • 对象的实例方法的方法引用
  • 类的实例方法的方法引用
  • 无参构造器引用
  • 有参构造器引用

3.1 静态方法的方法引用

@Test
public void test(){
    Comparator<String> comparator = String::compareTo;
    int result = comparator.compare("abc", "cba");
    System.out.println("result = " + result);
}

3.2 实例方法的方法引用

@Test
public void test(){
    PrintStream ps = System.out;
    Consumer<String> consumer = ps::println;
    consumer.accept("使用方法引用");
}

3.3 类的实例方法的方法引用

@Test
public void test(){
    Student student = new Student();
    student.setName("Tom");
    
    Function<Student, String> function = Student::getName;
    String name = function.apply(student);
    System.out.println("name = " + name);
}

3.4 无参构造器引用

@Test
public void test4() {
    // 无参构造器的方法引用
    Supplier<Student> supplier = Student::new;
    Student student = supplier.get();
    student.setName("小红");
    System.out.println("student = " + student);

    // 有参构造器的方法引用
    BiFunction<Integer, String, Student> function = Student::new;
    Student student1 = function.apply(24, "小红");
    System.out.println("student = " + student1);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值