java8新特性回顾(一)---函数式接口和lamda表达式

来源:互联网 发布:常用编程软件有哪些 编辑:程序博客网 时间:2024/05/22 02:27

java9已经发布一阵子了,但是很多程序员还停留在jdk 6 7版本。一方面是因为老系统很难升级改造,另一方面jdk6也能满足绝大多数日常开发需求。就我个人而言,14年刚毕业进入工作时就开始接触java8,但直到今年来新公司接触的同事发现多数没有关注或者应用java8的新特性,且在一些场景下这些新特性确实能带来开发效率和代码质量的提升,因此前阵子做了个技术分享,也在这里做一下总结笔记。

1.函数式接口:

函数式接口,@FunctionalInterface,简称FI,简单的说,FI就是指仅含有一个抽象方法的接口,以@Functionalnterface标注。

@FunctionalInterfaceInterface FI{   abstract judge(int a);   abstract equals();      }


Java SE7中函数式接口Java SE8新增包java.util.function中的函数式接口java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.beans.PropertyChangeListenerPredicate<T>——接收 T 并返回 boolean
Consumer<T>——接收 T,不返回值
Function<T, R>——接收 T,返回 R
Supplier<T>——提供 T 对象,不接收值
UnaryOperator<T>——接收 T 对象,返回 T
BinaryOperator<T>——接收两个 T,返回 T
BiFunction<T, U, R>,它接收 T 对象和 U 对象,返回 R 对象

2.lambda表达式

定义:带有参数的表达式都被称为lambda表达式
格式:参数列表、箭头符号 -> 和函数体组成,函数体既可以是一个表达式,也可以是一个语句块
表达式:表达式会被执行然后返回执行结果。
语句块:语句块中的语句会被依次执行,就像方法中的语句一样。
return 语句会把控制权交给匿名方法的调用者。
break 和 continue 只能在循环中使用
如果函数体有返回值,那么函数体内部的每一条路径都必须返回值


示例:

(int x, int y )-> x + y
() -> 42
(String s) -> { System.out.println(s); }
Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);
new Thread(() -> {
  connectToService();
  sendNotification();
}).start();


3.目标类型和方法引用

函数式接口的名称并不是 lambda 表达式的一部分,编译器负责推导 lambda 表达式类型。这个 被期待的类型 被称为 目标类型。lambda 表达式只能出现在目标类型为函数式接口的上下文中。


方法引用和 lambda 表达式拥有相同的特性(例如,它们都需要一个目标类型,并需要被转化为函数式接口的实例),不过我们并不需要为方法引用提供方法体,我们可以直接通过方法名称引用已有方法。
Person[] people = ...
Comparator<Person> byName = Comparator.comparing(p -> p.getName());
Arrays.sort(people, byName);

Comparator<Person> byName = Comparator.comparing(Person::getName);


方法引用示例:

静态方法引用:ClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:ClassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new


举例:
Consumer<Integer> b1 = System::exit;    // void exit(int status)
Consumer<String[]> b2 = Arrays::sort;    // void sort(Object[] a)
Consumer<String[]> b3 = MyProgram::main;  // void main(String... args)
Runnable r = Myprogram::mapToInt        // void main(String... args
SocketImplFactory factory = MySocketImpl::new;
IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10) // 创建数组 int[10]


5.接口默认方法和静态方法

默认方法 利用面向对象的方式向接口增加新的行为。它是一种新的方法:接口方法可以是 抽象的 或是 默认的。默认方法拥有其默认实现,实现接口的类型通过继承得到该默认实现(如果类型没有覆盖该默认实现)。


默认方法不是抽象方法,所以我们可以放心的向函数式接口里增加默认方法,而不用担心函数式接口的单抽象方法限制。


除了默认方法,Java SE 8 还在允许在接口中定义 静态方法。这使得我们可以从接口直接调用和它相关的辅助方法(Helper method),而不是从其它的类中调用(之前这样的类往往以对应接口的复数命名,例如 Collections)




冲突解决:
1.类优先原则:如果父类中提供了具体实现方法,那么接口中具有相同名称和参数的默认方法会被忽略。
2.接口冲突:两个父接口提供相同的名称和参数类型的方法时,实现类必须重写该方法。



原创粉丝点击