java 8新特性 之 lambda表达式/函数式接口 剖析

函数式接口

函数式接口是指只含有一个抽象方法的接口 ,往往这些接口只是为了给实现类添加某些额外的功能(有时也叫功能性接口)。例如:

 方法类型

方法类型是用来描述函数式接口的,格式为 (抽象方法参数)->抽象方法返回类型 [throws XXXException] 例如:

java8通过函数式接口和函数式类型实现了语法层面的函数式编程,并且简化了了以往继承方式实现功能增强的繁琐性。下面一起来看一下jdk中的函数式接口和方法的实现。

jdk中的函数式编程实现

@FunctionalInterface注解

package java.lang;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

这个注解用来标记函数式接口,但没有强制性约束,编译器会对符合函数式接口定义的接口采取对应的策略而不会因为没有标注此注解而忽略对函数式功能的解析。

手动撸一个函数式编程的例子

函数式接口(并未加函数式接口注解):

package com.test;

public interface SingleOrNot {
	boolean isSingle(Integer i);
}

 含有使用函数式接口作为方法参数的方法的类:

package com.test;

import java.util.List;

public class Instance {
	public static void printSingle(List<Integer> list , SingleOrNot func) {
		for(Integer i:list) {
			if(func.isSingle(i)) {
				System.out.println(i);
			}
		}
	}
}

测试代码:

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.junit.Test;

public class TestFunc {
	
	@Test
	public void testIsSingle() {
		Random random=new Random();
		List<Integer> list=new ArrayList<>();
		for(int i=0;i<100;i++) {
			list.add(random.nextInt(10000));
		}
		Instance.printSingle(list, i->i%2!=0);
	}
}

打印结果为:

4583 9525 1019 1445 591 1081 2019 1945 9937 9381 2867 5285 7093 1289 3857 7267 1521 9027 4841 9457 6743 5169 7573 3159 3201 5399 4171 6877 5683 1491 7501 2197 919 5721 7109 2677 9705 8349 51 4501 2753 1651 3141 1161 8967 1825 2277 743 

该例子实现了打印随机生成的100个数中的奇数的功能,其中的函数式接口就是SingleOrNot 接口,其实这样定义函数式接口的名字有些局限了,该函数式接口可以作为任何函数类型为(Integer)-> boolean的实现的抽象接口,改为IntToBoolean更为合适

更函数化一点

上面的例子是先定义了一个函数式接口,然后在方法中使用该接口类型,在使用时传递实现的方法体,习惯了函数式编程的人可能感觉有点别扭,就不能直接把函数类型作为参数么?这样不是更函数化一点么?jdk确实考虑到了这点,java.util.function.Function类就允许你将符合某一函数类型的的实现作为参数传递,而不仅限于特定接口的参数,下面提供了上面小例子更函数化的版本

含有函数参数方法的类:

package com.test2;

import java.util.List;
import java.util.function.Function;

public class Instance {
	public static void printSingle(List<Integer> list , Function<Integer, Boolean> func) {
		for(Integer i:list) {
			if(func.apply(i)) {
				System.out.print(i+" ");
			}
		}
	}
}

测试类:

package com.test2;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.junit.Test;

public class TestFunc {
	
	@Test
	public void testIsSingle() {
		Random random=new Random();
		List<Integer> list=new ArrayList<>();
		for(int i=0;i<100;i++) {
			list.add(random.nextInt(10000));
		}
		Instance.printSingle(list, i->i%2!=0);
	}
}

打印结果:

2767 2905 8665 6447 7095 6247 8185 23 3303 6391 2125 2353 3341 5107 5123 6023 909 4875 487 5583 3579 1461 1817 2413 6089 1301 9193 3681 2665 4837 1197 4115 923 291 625 3125 6459 213 2055 215 5531 4567 6465 2263 1039 3751 6975 263 

java.util.function下面定义了很多函数化编程接口,提供了诸如接受两个参数的函数类型接口BiConsumer,无参的函数类型接口Supplier等等,但是对于任意定义的函数类型貌似还不支持,比如直接用lambda表达式作为函数类型来修饰函数的引用还做不到,这大概和jvm不支持类型膨胀有关(像C++就支持类型膨胀,每一个泛型类的具体类都有真正的类型,函数指针可以指向任意类型的函数),不过这些便捷的操作也足够开发中使用了。

lambda表达式的语法

(参数变量列表)->{

函数体;

return 返回值;
}

(参数变量列表)->表达式

比如:

i->i%2!=0   

<=>

i->{return i%2!=0;}

语法没什么说的,多用两次就会了,主要了解内部的原理和思想

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值