Lambda、Stream与新增内容
1.interface新增内容
JDK1.8新增 :
1)静态方法 : 跟随接口名使用
2)默认方法 : 显示 通过default修饰的方法
可以在实现类中重写
需要通过实现类对象调用
JDK9新增 :
私有方法 : 被private关键字修饰
不能在外部类中使用
只能在接口中的默认方法中调用
public class Class001_Interface {
public static void main(String[] args) {
Smoke.testStatic();
new Impl().testDefault();
}
}
interface Smoke{
void smoking();
//静态方法
public static void testStatic(){
System.out.println("接口中的静态方法");
}
//默认方法
default void testDefault(){
System.out.println("默认方法....");
testPrivate();
}
//私有方法
private void testPrivate(){
System.out.println("私有方法...");
}
}
class Impl implements Smoke{
@Override
public void smoking() {
}
@Override
public void testDefault() {
System.out.println("重写的默认方法....");
}
}
2.Lambda
例题一
调用Collections.sort()方法对List集合中的数据做默认升序排序,通过定值排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda作为参数传递
分析:
1.定制排序:指自定义比较器|定制排序
自然排序:内部比较器|自然排序
2.先比较年龄,年龄相同才比较姓名
Lambda表达式 : 将行为作为参数传递–>函数式编程
如果形参|引用为函数式接口类型,实参|赋值就可以为Lambda表达式
public static void main(String[] args) {
List<Employee> emps = Arrays.asList(
new Employee(103,"迪丽热巴",30,8888),
new Employee(101,"古力娜扎",28,7777),
new Employee(102,"易烊千玺",23,8888),
new Employee(104,"欧娜娜娜",28,7777)
);
//Collections.sort(emps); 检测Employee类型是否实现了内部比较器,如果是调用做升序排序,如果没有实现报错
System.out.println(emps);
//Collections.sort(emps,(x,y)->x.getId()-y.getId()); //根据员工编号做升序排序
Collections.sort(emps,(x,y)->{
if(x.getAge()==y.getAge()){
return y.getName().compareTo(x.getName());
}
return Integer.compare(x.getAge(),y.getAge());
}); //根据员工编号做升序排序
System.out.println(emps);
}
例题二
1)声明函数式接口,接口中声明抽象方法,public String getValue(String str)
2)声明类 TestLambda,类中编写方法使用接口作为参数,讲一个字符串转成大写,并作为方法的返回值
3)再将一个字符串的第2个和第4个索引位置进行截取子串
public class Class002_TestLambda {
public static void main(String[] args) {
System.out.println(strHandler("abc",s->s.toUpperCase()));;
System.out.println(strHandler("123abc456",s->s.substring(2,5)));;
}
//需求 : 对任意一个字符串做某种操作,返回结果
public static String strHandler(String str,MyFunction my){
return my.getValue(str);
}
}
//接口
@FunctionalInterface
interface MyFunction{
public String getValue(String str);
}
习题三
1)声明一个带两个泛型的函数式接口,发型类型为<T,R> T为参数,R为返回值
2)接口中声明对应抽象方法
3)在TestLambda类中声明方法,参数三个,两个long类型的参数,接口作为参数,接口实现中计算两个long型参数的和
4)再计算两个long型参数的乘积
public class Class003_TestLambda {
public static void main(String[] args) {
pera(100L,200L,(x,y)->x+y);
pera(100L,200L,(x,y)->x*y);
}
//对两个long类型数据的使用 ,输出结果
public static void pera(long l1,long l2,MyFunction2<Long,Long> my){
System.out.println(my.test(l1,l2));
}
}
@FunctionalInterface
interface MyFunction2<T,R>{
public R test(T t1,T t2);
}
3.函数式接口
java.util.function下的函数式接口
四大内置函数式接口
1.消费型接口:有参无返回值
Consumer
void accept(T t)
2.函数式接口:有参有反回值
Function<T,R>
R apply(T t)
3.段言型接口:有参返回布尔
Predicate
boolean test(T t)
4.供给型接口:无参有返回值
Supplier
T get()
public static void main(String[] args) {
happy(5000,m-> System.out.println("为PDD刷火箭消费"+m));
System.out.println(strHandler("DLGJGL",s->s.toLowerCase()));
System.out.println(test(10,()->(int)(Math.random()*(8-5+1)+5)));
Consumer c = a -> System.out.println("ss");
c.accept(10);
Function d = b-> b;
}
//消费
public static void happy(double money, Consumer<Double> con){
con.accept(money);
}
//对任意一个 字符串进行某种操作返回结果
public static String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
//生成指定个数的指定规则的随机整数
public static List<Integer> test(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for(int i=1;i<=num;i++){
list.add(sup.get());
}
return list;
}
方法引用
是用来简化Lambda表达式的,是Lambda表达式的另外一种表现形式。
简化条件要求 : 必须满足一下2个条件
1.当lambda体{}中的实现就是通过调用另外一个方法实现的,可以考虑是否可以通过方法引用简化
2. a)当lambda参数列表,返回值与内部引用方法的参数列表与返回值保持一致的时候 ----> 对象::成员方法 | 类名::静态方法
b)内部所引用方法的 返回值与lambda表达式的返回值一致,lambda参数列表的第一个参数作为调用内部方法的对象,lambda参数列表的第二个参数开始匹配内部引用方法参数列表 ----> 类名::成员方法
方法引用语法 ::
对象::成员方法
//分析 : 1. 满足 println() 2) a)满足 ===>对象::成员方法
list.forEach(i->{
System.out.println(i);
});
//变化后
list.forEach(System.out::println);
类名::静态方法
//求两个double中的最大值
//BiFunction<Double,Double,Double> fun = (x,y)->Math.max(x,y);
//分析 : 1. 满足 max() 2.a)满足 ===>类名::静态方法
BiFunction<Double,Double,Double> fun = Math::max;
类名::成员方法
//比较两个字符串是否相等
//BiPredicate<String,String> bi = (x,y)->x.equals(y);
//分析 : 1. 满足 equals 2. b) 类名::成员方法
BiPredicate<String,String> bi = String::equals;
Stream流
1.三者之间的差别
IO流 : 关注数据的传输
集合|数组 : 关注数据的存储
Stream流 : 关注数据的运算
将由数据源产生的元素序列进行流式运算
2.Stream流的使用步骤
1.获取创建Stream流
2.一些列流式中间操作
3.终止行为
3.Stream流的特点
1.Stream本身不存储数据
2.Stream的运算不影响数据源
3.所有中间操作都返回持有结果的新的流
4.流是一次性的流,一旦已经使用就被破坏,无法重复使用多次
5.延迟执行|惰性加载 : 当获取终止行为的时候所有的中间操作才会执行
4.获取Stream的方式
1.Collection–>stream()
List<Integer> ls = List.of(1,2,3,4,5);
Stream<Integer> s1 = ls.stream();
s1.forEach(System.out::println);
2.Arrays.stream()
String[] arr = {"aaa","bbb","ccc","ddd"};
Stream<String> s2 = Arrays.stream(arr);
s2.forEach(System.out::println);
3.Stream.of(…)
Stream<Integer> s3 = Stream.of(5,4,3,2,1);
s3.forEach(System.out::println);
5.Stream中间操作 :
1.过滤 filter(Predicate<? super T> predicate) 返回由与给定谓词匹配的此流的元素组成的流。
2.截取 Stream limit(long maxSize) 返回由该流的元素组成的流,长度被截断为不超过maxSize 。
3.跳过 Stream skip(long n) 在丢弃流的前n元素后,返回由该流的剩余元素组成的流。
4.去重 Stream distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流。
根据equals与hashCode方法,需要根据内容重写
5.排序
Stream sorted() 返回由该流的元素组成的流,按自然顺序排序。
Stream sorted(Comparator<? super T> comparator) 返回由该流的元素组成的流,根据提供的Comparator排序。
emps.stream()
.filter(e->e.getAge()<30)
//.limit(4)
//.skip(1)
.distinct()
.sorted((x,y)->Integer.compare(x.getAge(),y.getAge()))
.forEach(System.out::println);