Java8新特性--Lambda表达式

Lambda     
 

Lambda表达式是JDK8中出现的新特性,其是函数接口的一种实现方式,用于代替匿名内部类。 
     函数式接口:Functional Interface,也称为功能性接口。简单来说,接口中可以包含多个方法,但仅能有一个自己的抽象方法,即接口的默认方法和静态方法并不影响一个接口 成为函数式接口。
 在JDK帮助文档中,FunctionInterface注解的说明中有关于函数接口的详细描述。 
 
An informative annotation type(信息注释类型) used to indicate(表明) that 【an interface type  declaration is intended(意图) to be a functional interface as defined by the Java Language Specification(规范)】. Conceptually(从概念上讲), a functional interface has exactly(仅仅) one  abstract method. Since(因为) default methods have an implementation, they are not abstract. If  an interface declares an abstract method 【overriding one of the public methods of  java.lang.Object】, that also does not count toward the interface's abstract method count(其不计入接口抽象方法计数) since any implementation of the interface will have an implementation from java.lang.Object or elsewhere(因为任何一个该接口的实现都将有一个来自于 java.lang.Object或其它地方的实现). 
@FunctionalInterface     
只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解
@FunctionalInterface。 
@FunctionalInterface接口来检验他是否是一个函数式接口。
lambda具体使用     
语法格式一无参无返回值
 

@Test
public void LambdaTest1(){语法格式二:无参有返回值 
语法格式三:有参有返回值 
TestFunctionInterFace testFunctionInterFace = new
TestFunctionInterFace() {
@Override
public void add() {
System.out.println("匿名内部类方式");
}
};
testFunctionInterFace.add();
}
@Test
public void LambdaTest2(){
TestFunctionInterFace testFunctionInterFace =()->{
System.out.println("Lambda方式");};
TestFunctionInterFace testFunctionInterFace1 =()-
>System.out.println("Lambda方式");
testFunctionInterFace1.add();
testFunctionInterFace.add();
}

语法格式二:无参有返回值

@Test
public void LambdaTest1(){
TestFunctionInterFace testFunctionInterFace = new
TestFunctionInterFace() {
@Override
public String add() {
return "匿名内部类方式";
}
};
String add = testFunctionInterFace.add();
System.out.println(add);
}
@Test
public void LambdaTest2(){
TestFunctionInterFace testFunctionInterFace=()-> "lambda表达式方式";
String add = testFunctionInterFace.add();
System.out.println(add);
}

语法格式三:有参有返回值  
 

@Test
public void LambdaTest1(){
TestFunctionInterFace testFunctionInterFace = new
TestFunctionInterFace() {
@Override
public String add(Integer I) {
return "熟悉的配方,还是原来的味道"+ I;
}
};


总结:小括号里放参数,如果Lambda表达式需要更复杂的语句块,则可以使用花括号将该语句块括起来。
类型声明:不需要声明参数类型,编译器可以统一识别参数值。
参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
大括号:如果主体包含了一个语句,就不需要使用大括号。
返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值
函数式接口     
JDK8中就根据接口方法参数与返回值的不同,定义好了若干内置的函数接口。在使用 Lambda表达式时,无需再定义那么多其它接口了,只需根据情况选择内置接口即可。 

Java内置四大核心函数式接口

函数式接口

参数类型

返回值类型

用途

Consumer消费型接口

T

void

对象类型为T的对象应用操作,包含方法 void accpectT t

Supplier供给型接口

T

返回类型为T的对象,包含方法:T get()

Function<T,R> 函数型接口

T

R

对类型为T的对象应用操作,并返回结果。结果是R类型对象。包含方法:R apply(Tt)

Predicate断定型接口

T

boolean

确定类型为T的对象是否满足某约束,并返回boolean 值。包含方法:boolean test(T t)


Predicate接口 
该接口用于判断输入的对象是否符合某个条件。该接口中只有一个抽象方法test(),三 个默认方法 and(与)、or(或)、negate(非),还有一个静态方法isEqual()。 
(1)test()
该方法会将参数值应用于接口Lambda表达式,测试该值的断言。
 

@Test
public void FunctionInterfaceTest3(){
Predicate<Integer> predicate=new Predicate<Integer>() {
@OverrideConsumer接口
Consumer,消费者,只有一个输入没有输出的函数接口。该接口有一个抽象方法accept(), 与一个默
认方法andThen()。
(1) accept()
该方法用于将参数值应用于接口Lambda表达式。
Supplier接口
public boolean test(Integer i) {
return i<8 ;
}
};
boolean test = predicate.test(9);//true
System.out.println(test);
}
@Test
public void FunctionInterfaceTest4(){
Predicate<Integer> predicate=i->i<8;//false
Predicate<Integer> predicate2=i->i<10;
boolean test = predicate.and(predicate2).test(7);
boolean test1 = predicate.or(predicate2).test(11);
boolean test3 = predicate.negate().test(7);
System.out.println(test);
System.out.println(test1);
System.out.println(test3);
}

Consumer接口
Consumer,消费者,只有一个输入没有输出的函数接口。该接口有一个抽象方法accept(), 与一个默认方法andThen()。 
(1) accept()
该方法用于将参数值应用于接口Lambda表达式。 
 

@Test
public void FunctionInterfaceTest5(){
Consumer<Integer> consumer= new Consumer<Integer>() {
@Override
public void accept(Integer i) {
System.out.println("今天休息了多长时间"+i);
}
};
consumer.accept(8);
}
@Test
public void FunctionInterfaceTest6(){
Consumer<Integer> consumer=i-> System.out.println("休息多少小时"+i);
consumer.accept(10);
}

Supplier接口 
Supplier,提供者,没有输入但有输出的函数接口。该接口只有一个抽象方法get(),用 于获取函数接口方法的返回值。 
 

@Test
public void FunctionInterfaceTest7(){
Supplier<String> supplier=new Supplier<String>() {
@Override
public String get() {
return"匿名内部类方式";
}
};
String s = supplier.get();
System.out.println(s);
}
@Test
public void FunctionInterfaceTest8(){
Supplier<String> supplier=()->"Lambda";
String s = supplier.get();
System.out.println(s);
}

Function接口 
只有一个输入,且有一个输出的函数接口。该接口中有一个抽象方法apply(),有两个默 认方法 andThen()与compose(),及一个静态方法identity()。 
(1)apply() 
该方法用于将参数值应用于接口方法。
该接口包含有两个默认方法andThen()与compose()。 
 andThen()是先执行前面的接口Lambda表达式,再将前面的执行结果作为后面Lambda  的输入参数执行后面的。
compose,组成,构成。compose()方法的执行恰好与andThen()的顺序相反。
identity()  这是Function接口包含的静态方法,其返回结果为该Function的输入参数值。 
   

Function<Integer,String> function=i->"你今年多大了"+i;
String apply = function.apply(25);
System.out.println(apply);
Function<Integer,Integer> function1=i->i*2;//4
Function<Integer,Integer> function2=i->i*i;//4 //16
Integer apply1 = function1.andThen(function2).apply(2);
Integer apply2 = function1.compose(function2).apply(2);
System.out.println(apply2);
// System.out.println(apply1);
System.out.println(Function.identity().apply(7));//5

方法引用:     
 
 我们用Lambda表达式来实现匿名方法。但有些情况下,我们用Lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作,在这种情况下,我们倾向于通过方法名来调用它,而Lambda表达式可以帮助我们实现这一要求,它使得Lambda在调用那些已经拥有方法名的方法的代码更简洁、更容易理解。方法引用可以理解为Lambda表达式的另外一种表现形式。

方法引用的分类                                                                                         

静态方法引用

类名::staticMethod

类名.staticMethod(args)

实例方法引用

实例名::实例方法名

persion.instMethod(args)

构建方法引用

类名::new

new Persion("王五")

Stream     
 
 
特性:     
Java 8 API添加了一个新的抽象称为流Stream
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理, 后由 终操作(terminal operation)得到前面处理的结果。
 
获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道,如图所示。
创建Stream     创建Stream方式一:集合创建Stream方式二:数组
创建Stream方式三:Stream of()流返回其元素为指定值的顺序有序流创建Stream方式四:创建无限流
 

@Test
public void StreamTest01(){
// 创建Stream方式一:集合
List<Integer> list = Arrays.asList();
list.stream().forEach(t-> System.out.println(t));
// 创建Stream方式二:数组方法 描述
filter(Predicate
e)
接收Lambda,从流中排除某些元素
distinct() 筛选,通过流生成的元素的hascode()和equals()去重复元素
limit(long
maxSize)
截断流,使其元素不超过指定给的数量
skip(long n) 跳过元素,返回 一个扔掉前n个元素的流,若流中不足n个元素,则返回一
个空流,与limit(n)互补
过滤
该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。
forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach
之后来执行其他Stream操作。
查询年龄等于16的学生信息
截取集合第一个元素
跳过前2个集合内容
distinct(),去重
int [] a={1,6,90};
Arrays.stream(a).forEach(t-> System.out.println(t));
// 创建Stream方式三:Stream of()流返回其元素为指定值的顺序有序流
Stream<Integer> integerStream = Stream.of(1, 2, 3);
integerStream.forEach(t-> System.out.println(t));
// 创建Stream方式四:创建无限流
Stream.generate(()->Math.random()).limit(4).forEach(t->
System.out.println(t));
}


 
 
过滤     
该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。 forEach需要一个函数来对过滤后的元素依次执行。forEach是一个 终操作,所以我们不能在forEach 之后来执行其他Stream操作。

方法

描述

filterPredicate e

接收Lambda,从流中排除某些元素

distinct()

筛选,通过流生成的元素的hascode()和equals()去重复元素

limit(long

maxSize)

截断流,使其元素不超过指定给的数量

skip(long n)

跳过元素,返回 一个扔掉前n个元素的流,若流中不足n个元素,则返回一个空流,limit(n)互补


查询年龄等于16的学生信息截取集合第一个元素跳过前2个集合内容
distinct(),去重
     

Student s1 = new Student("小高",15,"男");
Student s2= new Student("小李",16,"男");
Student s3 = new Student("小王",17,"男");
List<Student> students = Arrays.asList(s1, s2, s3);
List<Integer> list = Arrays.asList(1, 2, 3, 4, 3, 4);
// 查询年龄等于16的学生信息
students.stream().filter(t->t.getAge().equals(16)).forEach(s->
System.out.println(s));
// 截取集合第一个元素
long count = students.stream().limit(5).count();
System.out.println(count);
// 跳过前2个集合内容
students.stream().skip(2).forEach(s-> System.out.println(s));
// distinct(),
students.stream().distinct().forEach(s-> System.out.println(s));
long count1 = list.stream().distinct().count();
System.out.println(count1);

映射     
它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映 射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一 个新版本”而不是去“修改”)。

方法

描述

mapFunction f

接收一个函数为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素


求平方数找到姓名为小高的人

List<Integer> list = Arrays.asList(1, 2, 3, 4, 3, 4);
list.stream().map(n->n*2).forEach(t-> System.out.println(t));
Student s1 = new Student("小高",15,"男");
Student s2= new Student("小李",16,"男");
Student s3 = new Student("小王",17,"男");
List<Student> students = Arrays.asList(s1,s2,s3);
students.stream().map(s->s.getName()).filter(name->name.equals("小
高")).forEach(t-> System.out.println(t));


总结:从上面例子可以看出,map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。
排序     
自然排序
sorted( )   产生一个新流,其中按照自然排序
自定义排序
sorted(Comparator com  )    产生一个新流,其按照比较器的顺序来比较
 

//自然排序
List<Integer> list = Arrays.asList(1, 4, 3, 2, 7, 6, 4, 8, 10);
list.stream().sorted().forEach(t-> System.out.println(t));
//自定义排序
list.stream().sorted((e1,e2)->{
return Integer.compare(e1,e2) ;
}).forEach(t-> System.out.println(t));
Student s1 = new Student("小高",19,"男");
Student s2= new Student("小李",16,"男");
Student s3 = new Student("小王",17,"男");
List<Student> students = Arrays.asList(s1,s2,s3);
students.stream().sorted((e1,e2)->{
return Integer.compare(e1.getAge(),e2.getAge()) ;
}).forEach(t-> System.out.println(t));allMatch(Predicate p) 检查是否匹配所有元素

终止操作     

allMatch(Predicate p)

检查是否匹配所有元素

anyMatch(Predicate p)

检查是否至少匹配一个元素

noneMatch(Predicate p)

检查是否没有匹配所有元素

findFirst()

返回第一个元素

findAny()

返回当前流中的任意元素

count

返回流中元素总个数

max

获取 大值

min

小值

forEach()

迭代

Student s1 = new Student("小高",15,"男");
Student s2= new Student("小李",16,"男");
Student s3 = new Student("小王",19,"男");
List<Student> students = Arrays.asList(s1,s2,s3);
// allMatch(Predicate p)检查是所有元否匹配素\
boolean b = students.stream().allMatch(e -> e.getAge() > 13 &&
e.getAge() < 20); //false
// anyMatch(Predicate p) 检查是否至少匹配一个元素
boolean b2 = students.stream().anyMatch(e -> e.getAge() > 13 &&
e.getAge() < 16); //true
System.out.println(b2);
// System.out.println(b)


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值