您的位置:首页 > 编程语言 > Java开发

java8 函数式编程

2017-09-25 11:45 453 查看

1、简单的lamda表达式

如果一个接口中有多个方法,lamda不支持

interface A {
void testA();
}

interface B {
void testB(int x);
}

public class Test{

public static void main(String[] args) {
//不带参数的lamda表达式
A a = ()->{ /*TODO*/  };
//只有一条语句的lamda表达式
B b = x -> System.out.println(x);
//带参数的lamda表达式
B b1 = (int x) -> { /*TODO*/ };
}
}


2、流

public class Test{
static ArrayList<Integer> list = new ArrayList<>();
public static void main(String[] args) {
for (int i = 0; i < 30; i++) {
list.add(i);
}
//迭代器遍历
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
Integer data = iterator.next();
if(data == 10) {
System.out.println("find data==>"+10);
}
}
//使用流进行遍历
long count = list.stream().filter(data -> {
if(data==10) {
System.out.println("find data==>" + 10);
return true;
}
return false;
}).count();
System.out.println("count==>"+count);
}
}


以上都是遍历集合,查找并打印。

第一种使用迭代器操作

第二种使用流操作

filter为过滤方法,只是描述stream,但是不会做什么实质的工作。这种方法叫做懒性求值方法。

count会从stream产生值,叫做及早求值方法

2.1 一些常用的流操作

2.1.1

List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList());


of方法将一组初始值生成新的Stream。

collect方法将Stream中的值生成一个集合。

2.1.2

public static void main(String[] args) {
List<Integer> src = new ArrayList<>();
for (int i = 0; i < 10; i++)
src.add(i);

List<String> dst = src.stream()
.map(x -> String.valueOf(x))
.collect(Collectors.toList());
}


map中的参数其实是一个Function接口

map方法将参数从一种类型转换为另一种类型,这两种类型可以毫无关系。

2.1.3

List<Integer> dst = src.stream()
.filter(x -> x<10)
.collect(Collectors.toList());


filter的参数是Predicate接口,参数返回boolean。Stream值保留返回true的值。

2.1.4

import java.util.List;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;

List<Integer> list = Stream.of(asList(1, 2), asList(3, 4))
.flatMap(numbers -> numbers.stream())
.collect(toList());


flatmap将多个stream合并为一个stream

2.1.5

int min = Stream.of(1, 2, 3, 4, 5)
.min(Comparator.comparing(x -> x))
.get();


min/max 获取最小/最大值,需要实现Comparator接口

2.1.6

int count = Stream.of(1, 2, 3, 4, 5)
.reduce(0, (acc, element) -> acc+element);


reduce可以将一组值生成一个值,count,min, max都是reduce的一种。

需要注意的是在lamda函数其实是接口,会设计内部方法自动添加final字段

3.1 基本类型

IntSummaryStatistics res = list.stream().mapToInt(x -> x).summaryStatistics();
res.getSum();
res.getMax();


lamda封装了基本类型的操作,可以使用mapToxxx方法进行具体的转换。

调用summaryStatistics方法将返回xxxSummaryStatistics.里面封装了具体的求最大值、最小值、和、平均值等操作。

3.2 @FunctionalInterface

FunctionalInterface注解用于标识lamda接口,将代码块作为数据打包起来。

该注解会强制javac检查一个接口是否符合lamda函数接口的标准。如果该注解添加在枚举、类、另一个注解或者接口不止一个抽象方法,javac会报错。重构代码时,可以很容易发现问题。

3.3 方法引用

//data为Model类型
l//amda表达式片段为
data -> data.get();
//等价于
Model::get


3.4 collect收集器

3.4.1

LinkedBlockingQueue res = list.stream().collect(Collectors.toCollection(LinkedBlockingQueue::new));


Collectors.toCollection方法可以将集合转换为任意Set或Collectoion的子类

3.4.2

求值操作,如求最大值、最小值、平均值。需要注意返回类型。求值操作可以有具体的类型,如averagingInt、averagingXXX

class Model {
private int data;
public int getData() {
return data;
}
public Model(int data){
this.data = data;
}
}
public class Test{
public static void main(String[] args) {
List<Model> list = new ArrayList<>();
for (int i = 0; i < 10; i++)
list.add(new Model(i));
//平均值
double res = list.stream().collect(Collectors.averagingInt(Model::getData));
//求最大值
Optional<Model> d = list.stream().collect(maxBy(comparing(Model::getData)));
}
}


3.4.3

Map<Boolean, List<Model>> res = list.stream().collect(partitioningBy(x -> x.getData() > 5));


partitioningBy可以将一个集合按照条件分割成多个集合

3.4.4

组合收集器,可以将多个操作组合使用。

Map<Integer, Long> res = list.stream().collect(groupingBy(x -> x.getData(), counting()));


groupingBy可以将两个操作一起返回。

x -> x.getData()对应Map的Integer,counting()对应Map的Long

4、并行流处理

普通流调用parallel()或集合调用parallelStream()即可获得一个拥有并行能力的流。

并行处理的性能

数据的大小:并行处理是将数据分割、处理、合并。数据量足够大才能充分体现效率。

源数据结构:

ArrayList、数组或者IntStream支持随机读取的数据结构容易分割。性能较好

HashSet、TreeSet这些不容易分割,但是可以分割。性能一般

LinkedList、Streams.iterate等需要O(N)时间复杂度来分解问题,性能较差

装箱:基本类型比装箱类型效果好

cpu核心数:核心越多,效果越好

单元处理开销:花在流中每个元素的时间越长,效果越好

4.1 并行化数组操作

Arrays.parallelPrefix   //计算数组的和
Arrays.parallelSetAll   //更新数组元素
Arrays.parallelSort     //并行化对数组元素排序


5、调试

使用peek方法可以用于调试打印,不会影响正常的操作

list.stream().peek(natie -> System.out.println("==>"+natie.getData())).count();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: