目录
一 函数式接口
1 特点
2 核心函数式接口
1) Consumer
2) Supplier
3) Function
4) Predicate
5) 扩展:BiFunction
二 Stream
1 stream操作过程
1) 中间操作
2)终端操作
2 创建Stream对象
1) 通过集合获得Stream对象
2) 其他
3 终端操作
forEach()
count() , max() , min()
collect()
4 中间操作
filter()
map()
sorted()
limit() & skip()
接口中有且仅有一个抽方法
可以使用lambda表达式
可以使用@FunctionalInterface声明接口
在函数式接口中,可以定义多个默认的非抽象方法
jdk中给我们提供了一些常用的函数式接口
jdk1.8以前,就存在函数式特点接口 : Compartor ,Comparable
jdk1.8以后,提供了一些常用的函数式接口,其中有4个核心接口
消费型接口 ,传递参数,使用参数做一个处理。没有返回值 void accept(T t);
Consumer mc = (String s1)->{
System.out.println(s1.length());
};
mc.accept(s);
//-------------------------------------------
Consumer mc1 = (String s1)->{
System.out.println(s1.length());
};
Consumer mc2 = (String s1)->{
System.out.println(s1.toUpperCase());
};
Consumer mc3 = s1->{
System.out.println(s1.substring(0,5));
};
//mc2.accept(s);
//这是一个链式操作,先实现消费功能mc3,再实现消费功能mc2,最后实现消费功能mc1
mc3.andThen(mc2.andThen(mc1)).accept(s);
供给型接口, 无需要传递参数,返回对象 T get();
//需要产生一个随机数
//创建了一个对象 Object obj = new Object()
Supplier s1 = ()->{
Random r = new Random();
return r.nextInt(10);
};
Integer num = s1.get() ;
功能型接口,需要传递参数,根据参数做处理,将处理结果返回 R apply(T t); Function
String s = "dmc is good" ;
//需要实现功能,将字符串转换成大小
Function f1 = (String s1)->{
return s1.toUpperCase();
};
System.out.println( f1.apply(s) );
//---------------------------------------------
String s = "dmc is good" ;
//需要实现功能,将字符串转换成大小
Function f1 = (String s1)->{
System.out.println("1操作");
return s1.toUpperCase();
};
//System.out.println( f1.apply(s) );
Function f2 = s1->{
System.out.println("2操作");
return s1.substring(0,3);
};
//f1处理后,再进行一次f2的处理
//System.out.println( f1.andThen(f2).apply(s) );
//f1处理前,先进行一次f2的处理
System.out.println( f1.compose(f2).apply(s) );
断言型接口,传递参数,根据参数做判断,返回boolean boolean test(T t)
//判断user登录信息是否正确
Predicate p1 = (User user1)->{
return user1.uname.equals("dmc") && user1.upass.equals("123");
};
System.out.println(p1.test(user)?"登录成功":"登录失败");
//----------------------------------------------
User user = new User("dmc","1234") ;
//判断user登录信息是否正确
Predicate p1 = (User user1)->{
return user1.uname.equals("dmc") ;
};
Predicate p2 = (User user1)->{
return user1.upass.equals("123") ;
};
//函数式接口中的链式功能,基于的是一个对象
System.out.println(p1.or(p2).test(user)?"登录成功":"登录失败");
System.out.println(p1.negate().test(user));
R apply(T t,U u); BiFunction
Num num = new Num(10,20);
Function f1 = (num1)->num.x + num.y ;
//------------------------------------------
//二元操作功能
BiFunction b1 = (x , y)-> x+y ;
System.out.println(b1.apply(10,20));
stream操作分为2部分
如果没有终端操作,中间操作无法验证结果。
只有终端操作执行时,中间操作才开始执行。(在终端操作执行前,中间操作只是一个标记)
中间操作本身不会执行,只是一个标记,会在终端操作执行时才执行。
中间操作语法会返回一个Stream对象,可以以链式的方式增加多个中间操作(标记)
要么返回一个具体的数据,要么就执行遍历操作,什么都不返回(void)
整个流操作在执行终端操作方法时就结束了(如果有后续操作,也不是流操作,或者是一个新的流操作)
jdk1.8之后,为List , Set , Conllection 增加Stream()方法获得流对象
流对象中装载的就是集合中的数据
list.stream()
set.stream()
collection.stream()
//上面我们通过集合获得流的时候是先把数据存到集合里,在获得流的时候将数据存到流里
//下面的这种方法是直接将数据存到流里面
Stream.of(1,2,3,4,5);
//这种是通过传入一个Supplier,然后通过Supplier返回的对象存入到流中,通过limit的参数表示在流中存入多少个Supplier提供的对象
Stream.generate(()->"dmc").limit(100);
//这种是在流中存入数据1~100
Stream.iterate(1,(i)->++i).limit(100)
参数是个Consumer 消费型接口
//执行forEach方法时,底层就会遍历每一个元素,每次(底层)遍历获得一个元素,就会调用我们提供的消费功能进行处理(策略模式)
List cars = Arrays.asList(
new Car("宝马","蓝色",300000),
new Car("奔驰","黑色",400000),
new Car("奥迪","红色",450000),
new Car("保时捷","蓝色",600000),
new Car("本田","白色",2000000),
new Car("比亚迪","白色",220000),
new Car("理想","黑色",250000)
);
cars.stream()
.forEach(System.out::println);
Object obj = cars.stream()
.filter(car->car.color.equals("白色"))
.count();
System.out.println(obj);
//-------------------------------------------
Object obj = cars.stream()
.max((c1,c2)->c1.price - c2.price);
System.out.println(obj);
//汇总
//collect终端方法执行时,会遍历所有的元素,会将每个元素的price属性值收集起来,求和
Object obj = cars.stream()
.collect(Collectors.summingInt(car->car.price));
System.out.println(obj);
//分组(汇总)
Object obj = cars.stream()
.collect(Collectors.groupingBy(car->car.color));
System.out.println(obj);
Object obj = cars.stream()
.collect(Collectors.groupingBy(car->{
if(car.price<=300000){
return "便宜" ;
}else{
return "昂贵" ;
}
}));
System.out.println(obj);
参数是个Predict 断言型接口
cars.stream()
.filter(car->"黑色".equals(car.color))
.forEach(System.out::println);
参数是函数型接口 Function
//map就是在所有的属性中,抽取出部分需要的属性
//案例中就是在car的3个属性中,抽取出cname和price2个属性
cars.stream()
.map(car->{return new Car2(car.cname,car.price); })
.forEach(System.out::println);
List ---> List
可以没有参数,默认是按照升序排列的,还有一个带参数的方法Stream sorted(Comparator super T> comparator);
可以自定义排序规则
//排序
cars.stream()
.sorted((c1,c2)->c1.price-c2.price)
.forEach(System.out::println);
//关于比较器,可以看TreeSet
limit(long n1)表示从stream中取出n1的个数
skip(long n2) 表示跳过stream中的前面n2个数
//分页,从那条记录开始,取几条记录, 从0开始取3条(0,1,2),从3开始取3条(3,4,5),从6开始取3条(7,8,9)
cars.stream()
.sorted((c1,c2)->c1.price-c2.price)
.skip(4) //跳过几个,因为时从0开始条,这个条过几个,也可以理解为从第几个开始
.limit(3)
.forEach(System.out::println);