JDK8函数式编程快速入门干货.docx
《JDK8函数式编程快速入门干货.docx》由会员分享,可在线阅读,更多相关《JDK8函数式编程快速入门干货.docx(14页珍藏版)》请在冰豆网上搜索。
JDK8函数式编程快速入门干货
Java8引入函数式编程,极大地提高了编码效率,对于习惯了原有Java代码风格的coder,确实需要好好熟悉一番才能熟练地coding。
本文每一条讲解都配置了最简短的代码,适合快速入门或者字典使用,但阅读之后还是需要多看函数原型多看源码,灵活使用为好。
函数式编程语法
以Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept。
现在要定义一个Consumer对象,传统方式是这样的:
Consumerc=newConsumer(){
@Override
publicvoidaccept(Objecto){
System.out.println(o);
}
};
而使用函数式编程,可以这样定义:
Consumerc=(o)->{
System.out.println(o);
};
亦或者:
Consumerc=(o)->System.out.println(o);
简单理解函数式对象本质上还是一个对象,可以看做是其他方法的参数或者返回值,所以上面代码实际上可以这样:
Consumerc=System.out:
:
println;
常见的Java函数式接口
Consumer
顾名思义,Consumer的意思就是消费,即针对某个东西我们来使用它,因此它包含一个有形参无返回值的accept接口方法。
除了accept方法,还包含andThen这个方法,可以连续调用多个Consumer
publicstaticvoidconsumerTest(){
Consumerf1=System.out:
:
println;
Consumerf2=n->System.out.println(n+"-F2");
//执行f2之后,连续执行两次f2的Accept方法
f2.andThen(f1).andThen(f1).accept("test1");}
Supplier
Supplier代表的含义是“提供者”,因此它含有一个get方法,没有入参只能输出
Suppliersupplier=()->"Testsupplier";
supplier.get();
Function
Function也是一个函数式编程接口;它代表的含义是“函数”,而函数经常是有输入输出的,因此它含有一个apply方法,包含一个入参与一个返回值,可以用作装箱或者拆箱某个对象
/**
*Function测试
*/
publicstaticvoidfunctionTest(){
Functionf=s->s++;
Functiong=s->s*2;
/**
*下面表示在执行F时,先执行G,并且执行F时使用G的输出当作输入。
*相当于以下代码:
*Integera=g.apply
(1);
*System.out.println(f.apply(a));
*/
System.out.println(pose(g).apply
(1));
/**
*表示执行F的Apply后使用其返回的值当作输入再执行G的Apply;
*相当于以下代码
*Integera=f.apply
(1);
*System.out.println(g.apply(a));
*/
System.out.println(f.andThen(g).apply
(1));
/**
*identity方法会返回一个不进行任何处理的Function,即输出与输入值相等;
*/
System.out.println(Function.identity().apply("a"));}
Predicate
Predicate为函数式接口,predicate的中文意思是“断定”,意为判断某个东西是否满足某种条件;因此它包含test方法,根据输入值来做逻辑判断,其结果为True或者False,可以用作过滤对象
/**
*Predicate测试
*/privatestaticvoidpredicateTest(){
Predicatep=o->o.equals("test");
Predicateg=o->o.startsWith("t");
/**
*negate:
用于对原来的Predicate做取反处理;
*如当调用p.test("test")为True时,调用p.negate().test("test")就会是False;
*/
Assert.assertFalse(p.negate().test("test"));
/**
*and:
针对同一输入值,多个Predicate均返回True时返回True,否则返回False;
*/
Assert.assertTrue(p.and(g).test("test"));
/**
*or:
针对同一输入值,多个Predicate只要有一个返回True则返回True,否则返回False
*/
Assert.assertTrue(p.or(g).test("ta"));}
BinaryOperator
BinaryOperator接口用于执行lambda表达式,接受两个T类型的参数并返回一个T类型的返回值。
BinaryOperator中有两个静态方法,是用于比较两个数字或字符串的大小
minBy()获取更小的值,maxBy()获取更大的值。
示例如下:
BinaryOperatoradd=(n1,n2)->n1+n2;
System.out.println(add.apply(1,2));//3
System.out.println(BinaryOperator.maxBy(Integer:
:
compareTo).apply(1,2));//2
UnaryOperator
UnaryOperator继承于java.util.function.Function。
UnaryOperator接收一个T类型参数,并返回T类型的参数
UnaryOperatorddb=x->x+1;
System.out.println(ddb.apply("abc"));//abc1
函数式编程接口的使用
Stream类
Java8中,引入了流(Stream)的概念,这个流和以前我们使用的IO中的流并不太相同。
所有继承自Collection的接口都可以转换为Stream。
Stream的方法分为两类。
一类叫惰性求值,一类叫及早求值。
判断一个操作是惰性求值还是及早求值很简单:
只需看它的返回值。
如果返回值是Stream,那么是惰性求值。
其实可以这么理解,如果调用惰性求值方法,Stream只是记录下了这个惰性求值方法的过程,并没有去计算,等到调用及早求值方法后,就连同前面的一系列惰性求值方法顺序进行计算,返回结果。
Stream.惰性求值.惰性求值.....惰性求值.及早求值
Stream对象的创建
创建空的Stream对象
Streamstream=Stream.empty();
通过集合类中的stream或者parallelStream方法创建
Listlist=Arrays.asList("a","b","c","d");
StreamlistStream=list.stream();//获取串行的Stream对象
StreamparallelListStream=list.parallelStream();//获取并行的Stream对象
Stream具有平行处理能力,处理的过程会分而治之,也就是将一个大任务切分成多个小任务,这表示每个任务都是一个操作。
所以parallelListStream.forEach(out:
:
println)的输出结果不一定是abcd。
如果想要按照原本的stream顺序,可以使用parallelListStream.forEachOrdered(out:
:
println)
通过Stream中的of方法创建
Streams=Stream.of("a","b","c","d");
通过Stream中的iterate方法创建
Stream.iterate(1,item->item+1).limit(10).forEach(System.out:
:
println);
这段代码就是先获取一个无限长度的正整数集合的Stream,然后取出前10个打印。
千万记住使用limit方法,不然会无限打印下去。
通过Stream中的generate方法创建
Stream.generate(()->{
System.out.println("test");
returnMath.random();
}).limit(5).forEach(System.out:
:
println);
通过Stream中的concat方法连接两个Stream对象生成新的Stream对象
concat方法将两个Stream连接在一起,合成一个Stream。
若两个输入的Stream都是串行的,则新Stream也是串行的;若输入的Stream中任何一个是并行的,则新的Stream也是并行的
Stream.concat(Stream.of(1,2,3),Stream.of(4,5))
.forEach(integer->System.out.print(integer+""));//12345
Stream对象的函数列表
Stream对象提供多个非常有用的方法,这些方法可以分成两类:
中间操作:
将原始的Stream转换成另外一个Stream;如filter返回的是过滤后的Stream。
终止操作:
产生的是一个结果或者其它的复合操作;如count或者forEach操作。
方法都列举出来,但不是要求倒背如流,只是希望不重复造轮子
中间操作列表:
方法名
说明
sequential
返回一个相等的串行的Stream对象,如果原Stream对象已经是串行就可能会返回原对象
parallel
返回一个相等的并行的Stream对象,如果原Stream对象已经是并行的就会返回原对象
unordered
返回一个不关心顺序的Stream对象,如果原对象已经是这类型的对象就会返回原对象
onClose
返回一个相等的Steam对象,同时新的Stream对象在执行Close方法时会调用传入的Runnable对象
close
关闭Stream对象
mapToInt
元素一对一转换:
将原Stream中的使用传入的IntFunction加工后返回一个IntStream对象
distinct
去重:
返回一个去重后的Stream对象
sorted
排序:
返回排序后的Stream对象
peek
使用传入的Consumer对象对所有元素进行消费后,返回一个新的包含所有原来元素的Stream对象
limit
获取有限个元素组成新的Stream对象返回
skip
抛弃前指定个元素后使用剩下的元素组成新的Stream返回
takeWhile
如果Stream是有序的(Ordered),那么返回最长命中序列(符合传入的Predicate的最长命中序列)组成的Stream;如果是无序的,那么返回的是所有符合传入的Predicate的元素序列组成的Stream
dropWhile
与takeWhile相反,如果是有序的,返回除最长命中序列外的所有元素组成的Stream;如果是无序的,返回所有未命中的元素组成的Stream
终止操作列表:
方法名
说明
iterator
返回Stream中所有对象的迭代器
spliterator
返回对所有对象进行的spliterator对象
forEach
对所有元素进行迭代处理,无返回值
forEachOrdered
按Stream的Encounter所决定的序列进行迭代处理,无返回值
toArray
返回所有元素的数组
min
返回所有元素中最小值的Optional对象;如果Stream中无任何元素,那么返回的Optional对象为Empty
max
与min相反
count
所有元素个数
anyMatch
只要其中有一个元素满足传入的Predicate时返回True,否则返回False
allMatch
所有元素均满足传入的Predicate时返回True,否则False
noneMatch
所有元素均不满足传入的Predicate时返回True,否则False
findFirst
返回第一个元素的Optioanl对象;如果无元素返回的是空的Optional;如果Stream是无序的,那么任何元素都可能被返回
findAny
返回任意一个元素的Optional对象,如果无元素返回的是空的Optioanl
isParallel
判断是否当前Stream对象是并行的
常用函数示例
map
接收一个Funcation参数,用其对Stream中的所有元素进行处理,返回的Stream对象中的元素为Function对原元素处理后的结。
示例如下:
Streams=Stream.of("t1","t2");
s.map(n->n.concat(".txt")).forEach(System.out:
:
println);//ti.txtt2.txt
flatMap
元素一对多转换:
对原Stream中的所有元素使用传入的Function进行处理,每个元素经过处理后生成一个多个元素的Stream对象,然后将返回的所有Stream对象中的所有元素组合成一个统一的Stream并返回;
Streams=Stream.of("1t1","2t2");
s.flatMap(n->Stream.of(n.split("t"))).forEach(System.out:
:
println);//1122
filter
用于对Stream中的元素进行过滤,返回一个过滤后的Stream
Streams=Stream.of("t1","t2","aaa");
s.filter(n->n.contains("t")).forEach(System.out:
:
println);//t1t2
reduce
map用来归类,结果一般是一组数据,比如可以将list中的学生分数映射到一个新的stream中;reduce用来计算值,结果是一个值,比如计算最高分
ListpersonList=Arrays.asList(
newPerson(1,18,"小明"),
newPerson(1,19,"小强"),
newPerson(1,20,"小刚"),
newPerson(1,19,"小王"))
.stream()
.collect(Collectors.toList());
personList.stream()
.reduce((person1,person2)->person1.getAge()>person2.getAge()?
person1:
person2
)
.ifPresent((person)->System.out.println(JSON.toJSON(person)));
collect
可以将stream元素转换为不同类型的结果(List,Set,Map)。
转list用Collectors.toList();转set使用Collectors.toSet()。
示例(转List):
ListpersonList=Arrays.asList(
newPerson(1,18,"小明"),
newPerson(1,19,"小强"),
newPerson(1,19,"小王"))
.stream()
.filter(person->{
returnperson.getAge()==19;
})
.collect(Collectors.toList());
personList.forEach(person->System.out.println(person.getName()));
示例(转map):
Map>personMap=Arrays.asList(
newPerson(1,18,"小明"),
newPerson(1,19,"小强"),
newPerson(1,19,"小王"))
.stream()
.collect(Collectors.groupingBy(p->p.getAge()));
personMap.forEach((age,person)->System.out.println(age+":
"+JSON.toJSON(person)));
Optional类
这个类主要用来简化对空值的判断处理。
Optional实际上是对一个变量进行封装,它包含有一个属性value,实际上就是这个变量的值。
Optioanl对象的创建
它的默认构造函数是private类型的,因此要初始化一个Optional的对象无法通过其构造函数进行创建。
它提供了一系列的静态方法用于构建Optional对象:
empty
用于穿见一个空的Optional对象,其value属性为null。
例如:
Optionalo=Optional.empty();
of
根据传入的值构建一个Optional对象。
传入的值必须是非空值,否则如果传入的值为空值,则会抛出空指针异常。
例如:
o=Optional.of("test");
ofNullable
根据传入值构建一个Optional对象。
传入的值可以是空值,如果传入的值是空值,则与empty返回的结果是一样的。
Optional的使用
常用函数列表
方法名
说明
get
获取Value的值,如果Value值是空值,则会抛出NoSuchElementException异常;因此返回的Value值无需再做空值判断,只要没有抛出异常,都会是非空值
isPresent
Value是否为空值的判断
ifPresent
当Value不为空时,执行传入的Consumer
ifPresentOrElse
Value不为空时,执行传入的Consumer;否则执行传入的Runnable对象;
filter
当Value为空或者传入的Predicate对象调用test(value)返回False时,返回Empty对象;否则返回当前的Optional对象
map
一对一转换:
当Value为空时返回Empty对象,否则返回传入的Function执行apply(value)后的结果组装的Optional对象;
flatMap
一对多转换:
当Value为空时返回Empty对象,否则传入的Function执行apply(value)后返回的结果(其返回结果直接是Optional对象)
or
如果Value不为空,则返回当前的Optional对象;否则,返回传入的Supplier生成的Optional对象;
stream
如果Value为空,返回Stream对象的Empty值;否则返回Stream.of(value)的Stream对象;
orElse
Value不为空则返回Value,否则返回传入的值;
orElseGet
Value不为空则返回Value,否则返回传入的Supplier生成的值;
orElseThrow
Value不为空则返回Value,否则抛出Supplier中生成的异常对象;
简单示例
变量为空,则提供默认值
Mapmap=newHashMap<>();
map.put(1,"大米");
map.put(2,"小米");
map.put(3,"黑米");
Stringname=Optional.ofNullable(map.get(4)).orElse("none");
System.out.println(name);//none
如果用原本的代码写,就是这样的:
if(map.get(4)==null){
return"none";
}else{
returnmap.get(4);
}
如果变量为空时,抛异常的话
Optional.ofNullable(map.get(4)).orElseThrow(()->newException("test"));
如果变量为不为空则可以使用
如果按照原来的写法,如果不判断变量是否为空,并调用变量的成员方法的话,函数会抛空指针异常
Optional.ofNullable(map.get(4)).ifPresent(System.out:
:
println);
如果变量不为空则返回一定规则的返回值
returnuser.map(u->u.getUsername())
.map(name->name.toUpperCase())
.orElse(null);
如果上面这段转换成平时的Java代码,则变成这样:
Useruser=newUser....
if(user!
=null){
Stringname=user.getUsername();
if(name!
=null){
returnname.toUpperCase();
}else{
returnnull;
}
}else{
returnnull;
}
(哇,4000字的博客你都看得完。
。
。
)