Java高级(二)JDK8新特性

目录

基本概念

函数式编程

常用接口

Supplier接口

Consumer接口

 Predicate接口

Function接口

 Stream流

流式思想:

终结方法

延迟方法

静态方法

获取流的方法

方法引用

具体使用方法


基本概念

函数式接口:有且仅有一个抽象方法的接口

在java中,函数式编程的体现就是Lambda;Lambda可以被当作匿名内部类的“语法糖”,但是二者在原理上是不同的

@FunctionalInterface注解

作用:放在接口上,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错

Lambda会延迟执行:只有当调用接口对象时,Lambda才会被执行

使用Lambda表达式不会生成class文件

函数式编程

使用Lambda作为参数

 public static void main(String[] args) {
        new Thread(()-> System.out.println("线程启动")).start();
    }

使用Lambda作为返回值(返回一个比较器)

private static Comparator<String> test1(){
        return (a,b)->a.length()-b.length();
    }

常用接口

Supplier接口

Supplier<T>接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据

        没有形参、返回指定的数据类型数据

案例:求数组最大值

 private static int max(Supplier<Integer> supplier){
        return supplier.get();
    }
    public static void main(String[] args) {
        int[] ints={1,2,3,11,33,133,22,5};
        int max=max(()->{
            int i=ints[0];
            for (int anInt : ints) {
                if(anInt>i){i=anInt;}
            }
            return i;
        });
        System.out.println(max);
    }

Consumer接口

Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据至于具体怎么消费(使用),需要自定义(输出,计算....)

Consumer接口的默认方法andThen  :需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费 (一个数据 分别进行多次处理)

        有形参、无返回值

案例:格式化打印

 public static void test(ArrayList<String> arrayList, Consumer<String> consumer,Consumer<String> consumer1){
        for (String s : arrayList) {
            consumer.andThen(consumer1).accept(s);//同一个数据两次处理
        }
    }
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三,12");
        list.add("李四,34");
        test(list,(s)-> System.out.print("姓名:"+s.split(",")[0])
        ,(s)-> System.out.println("\t年龄:"+s.split(",")[1]));
    }

 Predicate接口

对某种数据类型的数据进行判断,结果返回一个boolean值

 boolean test(T t):用来对指定数据类型数据进行判断的方法

        有形参、返回boolean、用于逻辑判断

默认方法:and、or、negate就是(与或非)

示例代码

 private static ArrayList<Integer>test_and(ArrayList<Integer>list, Predicate<Integer>predicate1,Predicate<Integer>predicate2){
        ArrayList<Integer> arrayList = new ArrayList<>();//两种条件都符合时 数据进入新的集合 并且返回
        for (Integer integer : list) {
           if( predicate1.and(predicate2).test(integer)){
               arrayList.add(integer);
           }
        }
        return arrayList;
    }

    private static ArrayList<Integer>test_or(ArrayList<Integer>list, Predicate<Integer>predicate1,Predicate<Integer>predicate2){
        ArrayList<Integer> arrayList = new ArrayList<>();//两种条件满足一个时 数据进入新的集合 并且返回
        for (Integer integer : list) {
            if( predicate1.or(predicate2).test(integer)){
                arrayList.add(integer);
            }
        }
        return arrayList;
    }
    private static void test_no( Predicate<String>predicate1){
        System.out.println("条件求反:"+predicate1.negate().test("123345"));//非运算
    }
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        Collections.addAll(arrayList,1,32,11,49,2,4,123,49);
        //大于10且小于40的数字
        ArrayList<Integer> arrayList1 = test_and(arrayList, (i) -> i > 10, (i) -> i < 40);
        System.out.println(arrayList1);//[32, 11]
        //小于10或大于40的数字
        ArrayList<Integer> arrayList2 = test_or(arrayList, (i) -> i < 10, (i) -> i > 40);
        System.out.println(arrayList2);//[1, 49, 2, 4, 123, 49]
        //非运算
        test_no(s->s.length()>4);//条件求反:false
    }

Function接口

java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据, 前者称为前置条件,后者称为后置条件。
Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。使用的场景例如:将String类型转换为Integer类型。

默认方法:andThen 用来进行组合操作。例如:A.andThen(B).apply(s):将s传入A,再将A返回的值传入B,最后返回B运算的值

        主要应用于类型转换

示例代码:连续进行类型转换

private static int test(String s, Function<String,Integer> function1,Function<Integer,Integer>function2){
        return function1.andThen(function2).apply(s);
    }
    public static void main(String[] args) {
        test("12",(s)->Integer.parseInt(s),(i)->{
            System.out.println(++i);
            return i;
        });
    }

 Stream流

以前对集合操作的时候,总是循环、循环、再循环。循环只是方式,不是目的。线性循环还有一个缺点只能遍历一次,如果还有其他操作还需要重新进行循环

Lambda的衍生物Stream(只考虑目的,不用考虑实现方式)

流式思想:


类似于流水线,一步一步的执行,中间的延迟方法都会返回一个流对象(流对象本身),最后会有终结方法

Stream流对象只能使用一次(每个模型(就是流对象)使用完后 都会自动销毁)

特点:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道
  • 内部迭代:Stream提供了内部迭代的方式,流可以直接调用遍历方法。

终结方法

  • void forEach(Consumer<? super T> action); 接收每一个参数 对其处理
  • long count();统计元素个数

延迟方法

  • Stream<T> filter(Predicate<? super T> predicate);将一个流转换成子集流,进行过滤
  • <R> Stream<R> map(Function<? super T, ? extends R> mapper);映射 可以将集合内的所有元素进行类型转换
  • Stream<T> skip(long n);跳过前几个
  • Stream<T> limit(long maxSize);取用前几个

静态方法

  • static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b):将两个流合并到一起

获取流的方法

  • 根据Collection获取流:stream方法
  • 根据Map获取流:单独获取键值对的Set集合,再调用stream方法
  • 根据数组获取流:Stream.of(数组对象)

示例代码

public static void main(String[] args) {
        Integer[] ints={1,2,3,11,33,133,22,5};
        String[] strings={"张三","李四","王五","赵六","张三丰"};
        Stream<Integer> ints1 = Stream.of(ints);//获得stream对象
        Stream<String> strings1 = Stream.of(strings);//获得stream对象
        //使用过滤器 大于5小于150 最后输出
        Stream<Integer> stream1 = ints1.filter(i -> i > 5).filter(i -> i < 150);//ints1已经使用过了 不能再一次使用
        //姓张且长度大于2 的姓名
        Stream<String> stream2 = strings1.filter(s -> s.startsWith("张")).filter(s -> s.length() > 2);
        Stream<? extends Serializable> concat = Stream.concat(stream1, stream2);//进行拼接
        concat.forEach(i-> System.out.print(i+"\t"));//11	33	133	22	张三丰
        Stream<Integer> ints2 = Stream.of(ints);//获得stream对象
        System.out.println();
        //跳过前两个 取用前四个
        ints2.skip(2).limit(4).forEach(i-> System.out.print(i+"\t"));//3	11	33	133
    }

方法引用

方法引用是Lambda表达式的一种简写方法

Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型

 public static void main(String[] args) {
        //printstring("HELLO",s-> System.out.println(s));
        printstring("hello", System.out::println);
    }
System.out::println等价于s-> System.out.println(s)

具体使用方法

  • 通过对象名使用成员方法  对象名::成员方法名
  • 通过类名称引用静态方法  类名::方法名  例如:Math::abs
  • 通过super引用成员方法 supper::方法名
  • 通过this引用成员方法 this::方法名
  • 类的构造器引用 类名称::new 例如:name ‐> new Person(name)等价于Person::new
  • 数组的构造器引用  length -> new int[length] 等价于int[]::new

示例代码

//父子之间的方法引用(子类调用带有函数式接口的方法,将参数传递给父类方法(无参的话之间调用父类的方法))
public class Zi extends Fu{
    @Override
    public void sey() {
        System.out.println("我子类");
    }
    public void method(test1 t){
        t.printaaa();
    }
    public void show(){
        method(super::sey);//我是父亲
        method(this::sey);//我子类
    }
}
//类的构造器的引用
  private static person buind(String name,int age,builder builder){
        //接口功能获取个参数 建立对象
        return builder.test2(name,age);
    }
    public static void main(String[] args) {
        System.out.println( buind("王欢",12,person::new).toString());//person{name='王欢', age=12}
    }
//数组构造器的引用
private static int[] binder(int l,test3 test3){
        //接口的作用 接收一个参数(数组长度) 创建数组对象
        return test3.num(l);
    }
    public static void main(String[] args) {
        int[] binder = binder(12, int[]::new);
        System.out.println(binder.length);//12
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值