在scala中有非常方便的map,filter,reduce等对集合进行一系列操作的方法
那么我们想在java中实现这些方法该怎么编写程序呢?
首先我们想想到,要对java中的集合进行功能扩展,有两种方式:
1.装饰者模式
2.继承
使用装饰者模式时,可以编写一个包装类,在包装类里写上我们想要实现的方法模型
然后在方法的参数列表中要求传入一个接口,在接口中定义一个类似于函数的标准,
具体要实现的功能,由测试类new匿名内部类的时候自己传入
为了使我们可以传入任意类型的数据,所以我们在定义参数类型时,可以使用范型,范型除了能约束集合中的数据类型之外,还能使我们的代码变得更加灵活
包装类
import java.util.ArrayList;
/**
* 自定义一个MyList,继承ArrayList,这样MyList就拥有了ArrayList所有的功能
* 给定MyList集合的类型和ArrayList集合类型保持一致,都为A
* 否则遍历旧集合时,就会出现找不到类型A的问题
*/
public class MyList<A> extends ArrayList<A> {
//定义一个map方法,参数列表中传入一个想要实现的逻辑的接口,返回的新集合可能数据类型会发生改变,所以需要再加入一个范型<B>
//范型也可以定义在方法列表中,放在public之后,返回值类型之前,注意返回的是我们自定义的MyList集合,范型为<B>
//这样我们在调用map方法之后,因为返回的是MyList集合,又可以继续点MyList类中的方法,形成类似流式运算的流程
public <B> MyList<B> map(Function1<A,B> f1) {
//创建一个新的集合
MyList<B> nlist = new MyList<>();
//遍历老的集合,老的集合即调用该方法时的本类的对象(this)
for (A l : this) {
//调用Function1中的apply方法,执行我们自定义的逻辑
B apply = f1.apply(l);
//将新的值放入新的集合中
nlist.add(apply);
}
//返回新集合
return nlist;
}
//定义一个filter方法,因为筛选过后的数据类型一般都和原数据类型相同,所以传入的类型和返回的类型都为A
//筛选时返回的结果要么是true,要么是false,所以直接给Function1的返回类型为Boolean
public MyList<A> filter(Function1<A,Boolean> f1){
MyList<A> nlist = new MyList<>();
for (A a : this) {
Boolean apply = f1.apply(a);
if (apply){
nlist.add(a);
}
}
return nlist;
}
//reduce方法,聚合前后类型都相同,所以直接一个范型就可以了
public A reduce(Function2<A> f2){
//立一个falg,判断遍历集合时是否来的是第一个值
Boolean falg = true;
//创建一个中间值,用于叠加
A temp = null;
for (A a : this) {
if (falg){
//是第一个值,就将值给到temp,并将falg改为false
temp=a;
falg=false;
}else {
//过了第一个值之后,就可以调用接口中的apply方法,将中间值和当前值传入,
//并执行实现该接口时传入的逻辑(将两个数相加),执行完之后,又将结果给到中间值
//这样中间值就将所有的值都加到了它身上
temp = f2.apply(temp, a);
}
}
//最后返回叠加了所以值的中间值即可
return temp;
}
}
定义标准的接口
//定义两个范型,A1为传入参数类型,B1为返回值类型
public interface Function1<A1,B1> {
B1 apply(A1 t);
}
//reduce方法需要传入两个参数,所以需要定义一个两个参数的接口
public interface Function2<A> {
A apply(A x1,A x2);
}
测试类
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MyListText {
public static void main(String[] args) {
MyList<Integer> list = new MyList();
list.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9));
//调用方法一:匿名内部类
Integer reduce = list.map(new Function1<Integer, Integer>() {
@Override
public Integer apply(Integer t) {
return t * 10;
}
}).filter(new Function1<Integer, Boolean>() {
@Override
public Boolean apply(Integer t) {
return t > 5;
}
}).reduce(new Function2<Integer>() {
@Override
public Integer apply(Integer x1, Integer x2) {
return x1 + x2;
}
});
System.out.println(reduce); //450
//调用方法二:Lambda表达式
String reduce1 = list.filter(x -> x > 5)
.map(x -> "doit" + x * 10)
.reduce((x1, x2) -> x1 + x2);
System.out.println(reduce1); //doit60doit70doit80doit90
}
}
java自带的流式编程
public class MyListText {
public static void main(String[] args) {
List<Integer> list = new ArrayList();
list.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9));
//将集合中的数据变成水流状的,放入流中进行一步一步的操作,通过filter和map方法之后,返回的是一个Stream类型的数据
Stream<Integer> stream = list.stream().filter(x -> x > 6).map(x -> x * x);
//可以通过collect(Collectors.toList())方法将Stream类型的数据转回List
List<Integer> collect = stream.collect(Collectors.toList());
//reduce方法聚合后,返回的是Optional类型的数据,因为聚合后的数据可能存在也可能不存在
Optional<Integer> reduce2 = list.stream().filter(x -> x > 6).map(x -> x * x).reduce((x1, x2) -> x1 + x2);
//get()方法可以取出它里面的值
Integer integer = reduce2.get();
System.out.println(integer); //194
}
}