jdk1.8新特性
解决的问题:
1.开发者可以使用Java8编写复杂的处理算法,只需要简单修改一个方法,就能让代码在多核CPU上高效运行。增加lambda表达式。
2.使用函数式编程的思想,面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。现实世界中,数据和行为存,程序也是如此,因此这两种编程方式我们都得学。通过函数式编程,程序员能编写出更容易阅读的代码——这种代码更多地表达了业务逻辑,而不是从机制上如何实现。易读的代码也易于维护、更可靠、更不容易出错。
lambda 函数编程
3.Java 8还让集合类可以拥有一些额外的方法:
default(默认)方法。程序员在维护自己的类库时,可以使用这些方法。
在接口中可以定义默认方法:
接口{
default(){
很多代码
}
规范2();
规范1();
}
可以在不修改 以前代码的 情况下 添加新功能
接口{
规范2();
规范1();
default 新规范(){
}
}
实现类:
default默认方法可以重写.
1.接口中方法
通过在方法前加上default关键字就可以在接口中写方法的默认实现
大家熟知的List接口,如果需要新添加一个功能,但是又不想对已有的实现类代码修改, 怎么实现呢?
思考:接口中的默认方法出现会带来什么好处?
答: 对接口中的功能 增强
这使得我们不需要在接口中增加方法后对已经存在的每个实现类进行实现该方法,做到了平滑的增强。
Java 8中的接口现在支持在声明方法的同时提供实现,通过两种方式可以完成这种操作。
Collections :集合工具类
Collection :接口 :Set List 父类
2.接口内声明静态方法
同时定义接口以及工具辅助类(companion class)是Java语言常用的一种模式,工具类定义了与接口实例协作的很多静态方法
比如,Collections就是处理Collection对象的辅助类。
由于静态方法可以存在于接口内部,
你代码中的这些辅助类就没有了存在的必要,
你可以把这些静态方法转移到接口内部。
为了保持后向的兼容性,这些类依然会存在于Java应用程序的接口之中。
在接口中可以提供静态的方法
例:
public interface InterfaceTest {
public void add();
public static void show() {
System.out.println("这个是接口中的静态方法");
}
public static void minus() {
System.out.println("这个也是接口中的静态方法");
}
}
调用接口中静态方法:
接口名.方法名(参数);
public static void main(String[] args) {
InterfaceTest.minus();
InterfaceTest.minus();
}
3.接口中默认方法
接口包含的方法在它的实现类中也可以不提供实现
efault的方法实现会作为接口的一部分由实现类继承(所以命名为默认实现),而无需由实现类提供。
默认方法由default修饰符修饰,并像类中声明的其他方法一样包含方法体。
例:
public interface DefaultTest {
public default void show1() {
System.out.println("这个是默认方法 1");
}
public default void show2() {
System.out.println("这个是默认方法 2");
}
public default void show3() {
System.out.println("这个是默认方法 3");
}
}
interface DD extends DefaultTest{
//覆盖父接口中的show2方法
public default void show2() {
System.out.println("这个是我重写以后的 方法 2");
}
}
//实现类
class Test implements DD{
public void show3(){
//在实现类中调用父接口中的默认方法show3
DD.super.show3();
System.out.println("...");
}
}
测试:
public static void main(String[] args) {
Test t = new Test();
t.show1();
t.show2();
t.show3();
}
1.函数式编程
以函数思维做为核心,在这种思维的角度去思考问题,最重要的基础是函数的输入和输出,使用不可变值和函数,
【函数对一个值进行处理,映射成另任意函数式接口类型的一个值】
Comparator t = 函数(值);
1: 函数式接口
函数式接口就是只定义一个抽象方法的接口。
注:哪怕有很多默认方法,
只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。
2: 函数式接口的作用
Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例 (具体说来,是函数式接口一个具体实现的实例)。你用匿名内部类也可以完成同样的事情,只不过比较笨拙。
3: 函数描述符
函数式接口中的抽象方法的签名基本上就是Lambda表达式的签名,我们将这种抽象方法叫作函数描述符。
lambda:表达式
() -> {}
4,声明函数式接口 @FunctionalInterface
这个标注用于表示该接口会设计成一个函数式接口
2.lambda表达式
可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称。
函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
传递——Lambda表达式可以作为参数传递给方法或存储在变量中。(行为参数)
简洁——无需像匿名类那样写很多模板代码。
总结:快速实现接口中的方法【lambda简单化的匿名函数】
1.基本语法
函数式接口类型 变量名 = ()->{}
使用lambda表达式实现配合Collections完成排序功能。
对比,匿名内部类
感受:lambda是快速实现接口中的方法
自定义接口:里面只有一个抽象方法
自定义测试类: 里面的某一个方法 参数为 接口类型
main : 进行测试。
2.lambda表达式用法:
1.没有参数,没有返回值
()->{}
注:如果大括号里只有一句代码 ()->代码 该代码不要;号结尾
2.没有参数,有返回值
()->{return 值;}
注:如果大括号里只有一句代码 ()->返回值 该代码不要;号结尾
3.有一个参数,没有返回值
(a)->{System.out.println(a)}
注:如果大括号里只有一句代码 (a)->代码 该代码不要;号结尾
4.有一个参数,有返回值
(a)->{a++;return a;}
注:如果大括号里只有一句代码 (a)->返回值 该代码不要;号结尾
注:如果只有一个参数,()也可以不写。
a->{};
5.有两个参数,没有返回值
(a,b)->{a++;System.out.println(b);}
注:如果大括号里只有一句代码 (a,b)->代码 该代码不要;号结尾
6.有两个参数,有返回值
(a,b)->{a++;return a;}
注:如果大括号里只有一句代码 (a,b)->返回值 该代码不要;号结尾
注:大括号里的代码需要打分号。就是普通正常代码。
注:参数里面是不用谢参数类型的。
2.5,lambda中变量的问题:
lambda中可以使用成员变量,局部变量,但是使用过局部变量以后,该局部变量就必须为final,所以不能再修改了。
3:在函数式接口上使用lambda表达式
jdk8中新引入了几个函数式接口:
Predicate<T>接口 test(T t)
接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。
boolean test(T t);表示:t进行断言,返回true或者false,可以配合其他的方法使用,如filter();
Predicate接口是用来支持java函数式编程新增的一个接口,使用这个接口和lambda表达式就可以以更少的代码为API方法添加更多的动态行为。
还有两个默认方法 and or
/*
@FunctionalInterface
interface Predicate<T>{
boolean test(T t);
}
*/
public class LambdaTest4 {
public static void filter(List<String> languages, Predicate<String> condition) {
for(String name: languages) {
if(condition.test(name)) {
System.out.println(name + " ");
}
}
}
public static void main(String[] args) {
List<String> languages = Arrays.asList("Java", "html5","JavaScript", "C++", "hibernate", "PHP");
//开头是J的语言
filter(languages,(String name)->name.startsWith("J"));
//5结尾的
filter(languages,(String name)->name.endsWith("5"));
//所有的语言
filter(languages,(name)->true);
//一个都不显示
filter(languages,(name)->false);
//显示名字长度大于4
filter(languages,(name)->name.length()>4);
System.out.println("-----------------------");
//名字以J开头并且长度大于4的
Predicate<String> c1 = (name)->name.startsWith("J");
Predicate<String> c2 = (name)->name.length()>4;
filter(languages,c1.and(c2));
//名字不是以J开头
Predicate<String> c3 = (name)->name.startsWith("J");
filter(languages,c3.negate());
//名字以J开头或者长度小于4的
Predicate<String> c4 = (name)->name.startsWith("J");
Predicate<String> c5 = (name)->name.length()<4;
filter(languages,c4.or(c5));
//名字为Java的
filter(languages,Predicate.isEqual("Java"));
//判断俩个字符串是否相等
boolean test = Predicate.isEqual("hello").test("world");
System.out.println(test);
}
源代码解析:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
Function<T, R> 接口 R apply(T t); 有参数有返回值
参数 返回值
接收T对象,返回R对象
表示接受一个参数并产生结果的函数。
/*@FunctionalInterface
interface Function<T, R>{
R apply(T t);
}*/
public class LambdaTest6 {
public static <T, R> List<R> map(List<T> list,Function<T, R> f) {
List<R> result = new ArrayList<>();
for(T s: list){
result.add(f.apply(s));
}
return result;
}
public static void main(String[] args) {
List<Integer> list = map(
Arrays.asList("lambdas","in","action"),
(String s) -> s.length()
);
System.out.println(list);// [7, 2, 6]
}
}
Supplier<T> 接口 T get(); 没参数有返回值
返回值
代表结果供应商。
没有要求每次调用供应商时都会返回新的或不同的结果。
/*@FunctionalInterface
interface Supplier<T>{
T get();
}*/
public class LambdaTest7 {
public static void main(String[] args) {
//生成一个八位的随机字符串
Supplier<String> f = ()->{
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 8; i++) {
//生成[0,base.length)之间的随机数
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
};
System.out.println(f.get());
}
}
Consumer<T> 接口 void accept(T t); 有参数没返回值
参数 对给定的参数执行此操作
这个接口,接收一个泛型的参数T,然后调用accept,对这个参数做一系列的操作,没有返回值;
public class LambdaTest5 {
public static <T> void forEach(List<T> list, Consumer<T> c){
for(T i: list){
c.accept(i);
}
}
public static void main(String[] args) {
forEach(
Arrays.asList(1,2,3,4,5),
(Integer i) -> System.out.println(i)
);
}
}
另外需要注意的接口: 其用法和上面介绍的接口使用方式类同
BinaryOperator<T>接口 T apply(T t, T t) 将两个T作为输入,返回一个T作为输出
BiFunction<T, U, R>接口 R apply(T t, U u) 将一个T和一个U输入,返回一个R作为输出
BinaryOperator接口继承了BiFunction接口
public interface BinaryOperator<T> extends BiFunction<T,T,T>
BiConsumer<T, U>接口 void accept(T t, U u) 将俩个参数传入,没有返回值
4.java常用的函数式编程接口使用:
1.比较器
2.实现线程
3.绑定事件
4.集合数据排序