JAVA8 新特性的一些练习和简单使用 能快速上手

JAVA8 新特性主要内容部分:

  • 1.Lambda 表达式

  • 2.函数式接口

  • 3.方法引用与构造器引用

  • 4.Stream API

  • 5.接口中的默认方法与静态方法

  • 6.新时间日期API

  • 7.其他新特性

 

1.速度快、代码少、强大的stream 、便于并行、最大化减少空指针

 

2.哈希算法 hashmap  数组-链表-红黑树  加载因子0.75

 

3.ConcurrentHashMap  CAS算法  16

 

4.方法区 换成 MetaSpace 元空间  默认用物理内存 也可配置

      取消永久区

 

# 第一部分 Lambda 表达式

lambda: 匿名函数、可传递的代码链式编程

Lambda表达式的基础语法:java8中引入了一个新的操作符 “->” 箭头操作符将lambda表达式分为两部分:

1.左侧:参数列表  (接口中对应的抽象方法参数   函数式接口只有一个抽象方法)

2.右侧:表达式中所需执行的功能,即lambda体

 

语法格式1:无餐,无返回值

Runnable  r2 = () -> System.out.println("执行了");

语法格式2:有一个参数,且无返回值;小括号可以不写

Consumer<String> c = (x) -> System.out.println(x);

//Consumer<String> c = x -> System.out.println(x);

 c.accept("666");

语法格式3:有多个参数,有返回值,多条语句;小括号,大括号都不能省略

Comparator<Integer> t = (x,y) -> {

            System.out.println("函数式接口");

            return Integer.compare(x,y);

        };

语法格式4:若lambda体中只有一条语句时,return ,大括号都可以不写

                    参数列表数据类型可以不写,jvm 编译器可以上下文推断出数据类型,又称“类型推断”

Comparator<Integer> t = (x,y)  ->Integer.compare(x,y);

口诀:左右遇一括号省   左侧推断类型省   能省就省

二、Lambda 表达式 需要“函数式接口”的支持

函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionInterface 修饰,它可以检测是不是函数式接口

练习:

///1

List<Emloyee> emps = Arrays.asList(

    new Emloyee(11,"zhangsan","6666"),      
    new Emloyee(22,"李四","4444"),      
    new Emloyee(55,"李四5","54444"),    
    new Emloyee(33,"王五","55555555"),      
    new Emloyee(33,"王五2","2222555"),      
    new Emloyee(44,"zhaoliu","34125")       
    );

    @Test

    public void test() {
        Collections.sort(emps,(e,e2)->
        e.getAge()==e2.getAge() ?
        e.getName().compareTo(e2.getName()) :
        Integer.compare(e.getAge(),e2.getAge())
     );

       for (Emloyee e : emps) {
            System.out.println(e);
        }
    }

///2

public interface StringOpt {
    public String opt(String opt);
}



    // 字符串处理
    @Test
    public void test2() {
        String s = strHandler("\t\t  sfda dfdf  ", x -> x.trim() );
        System.out.println(s);
        String s2 = strHandler("abcde", x->  x.substring(2));
        System.out.println(s2);
    }

    public String strHandler(String  str,StringOpt so) {
        return so.opt(str);
    }

public interface MyFunction<T,R> {
    public R getValue(T t1,T t2);
}

    // 对于两个Long 型数据处理
    @Test
    public void test3() {
        op(100L,200L,(x,y) -> x + y);
        op(100L,200L,(x,y) -> x * y);
    }
    public  void op(Long l1,Long  l2,MyFunction<Long,Long> mf) {
        System.out.println(mf.getValue(l1, l2));
    }



@FunctionalInterface
public interface TestLambda<T> {
    public boolean test(T t);
}

2.1java 内置四大核心函数式接口
Consumer<T> 消费型接口             void   accept(T t); 
// 方式1
        Consumer<String> cs = new  Consumer<String>() {
            @Override
            public void accept(String t) {
                // TODO Auto-generated method  stub
                System.out.println(t);
            }
        };
        cs.accept("aaaaaaaaaaa");
        // Lambda方式2
        Consumer<String> cs1 = (x)->  System.out.println(x);
        cs1.accept("6666666666");


Supplier<T>    供给型接口                T     get();

    //Supplier<T>    供给型接口                T      get();
    @Test
    public void test4() {
        List<Integer> num = getNumList(10, ()  ->(int)(Math.random()*100));
        System.out.println(num);
    }

    ///需求 产生指定个数的整数,存放到集合中

    public List<Integer> getNumList(int  num,Supplier<Integer> sup){
        List<Integer> list = new  ArrayList<Integer>();
        for(int i = 0;i < num; i++) {
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }



Function<T,R>   函数型接口               R apply(T t);
//Function<T,R>   函数型接口               R  apply(T t);
    @Test
    public void test5() {
        String i = strHandler1("sssabfjd/t113",  x -> x.substring(0, 1));
        System.out.println(i);
    }

    //需求处理字符串
    public String strHandler1(String  str,Function<String, String>f) {
        return f.apply(str);
    }

Predicate<T>     断言型接口                boolean test(T t);                      
// Predicate<T>     断言型接口                 boolean test(T t);                      
    @Test
    public void test6() {
        List<String> s =  Arrays.asList("aa","hh","fhkaf","很好的");
        List<String> strList =  optString(s,x->x.length()>2);
        System.out.println(strList);
    }

    
    /// 将满足条件的字符串放到集合中
    public List<String> optString(List<String>  list,Predicate<String>pre){
        List<String> strList = new  ArrayList<>();
        for (String s : list) {
            if(pre.test(s)) {
                strList.add(s);
            }
        }
        return strList;
    }

    

 

常用的其他函数式接口:

BiFuntion<T,U,R>       R apply(T t,U u);

UnaryOperatot<T>     T apply(T t);  它是Function 的子接口

BinaryOperator<T>    void accept(T t1,T t2 );  是BiFunction 的子接口

BiConsumer<T,U>       void  accept(T t,U u);

 

 

三、  3.1方法引用

方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda 表达式的另一种表现形式)

主要有三种语法格式:

对象:: 实例方法名

类ishil :: 静态方法名

类 :: 实例方法名

 

注意:1. lambda 体中调用方法的参数列表与返回值类型,要与函数式接口这种抽象方法的函数列表与返回值一致

  1. 如果lambda 参数列表第一个是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName:: method  如:      

   BiPredicate<String, String> bp = (x,y)  -> x.equals(y);        BiPredicate<String, String> bp2 =  String::equals;

// 对象
    @Test
    public void test7() {
        PrintStream ps = System.out;
        Consumer<String> con = x ->  ps.println(x);
        con.accept("aaa");
        
        // 简化  左右类型要一致
        Consumer<String> con2  =System.out::println;
        con2.accept("6666");
    }
    
    @Test
    public void test8() {
        Emloyee e = new Emloyee();
        Supplier<String> sup = e::getName;
        String name = sup.get();
        System.out.println(name);
    }
    

    // 类--静态方法
    @Test
    public void test9() {
        Comparator<Integer> com =   Integer::compareTo;
        int c = com.compare(22, 11);
        System.out.println(c); // 1
    }



// 类--实例方法
    @Test
    public void test91() {
        BiPredicate<String, String> bp = (x,y)  -> x.equals(y);
        BiPredicate<String, String> bp2 =  String::equals;
        System.out.println(bp.test("11","aa"));
    }

 

2.3  构造器引用

ClassName::new

注意;需要调用的构造器参数列表要与函数值接口中参数列表一致;

 @Test
    public void test2() {
        Supplier<Employee> sup = () -> new  Employee();
        // 构造器引用
        Supplier<Employee> sup2 = Employee::new;
        Employee e = sup2.get();
        System.out.println(e); //Employee [id=0,  age=0, name=null, salary=null]
    }

3.2  数组引用

Type::new;

    // 数组引用
    @Test
    public void test3() {
        Function<Integer,String[]> fun = (x) -> new  String[x];  
        String[] strs = fun.apply(4);
        System.out.println(strs.length); //4
        
        Function<Integer,String[]> fun2 =  String[]::new;
        String[] str2 = fun2.apply(6);
        System.out.println(str2.length);//6
    }

四 Stream API 流

问题:什么是流Sream?

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算。”

① Stream 自己不会存储元素。

② Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③ Stream 是延迟执行的。 这就意味这他们会等到需要的结果时才执行。

 

三步走:

1.创建stream

    // 1. 可以通过 Collection系列集合框架 提供  xxx.stream() 或者parallelStream()

    // 2. 通过Arrays 中的静态方法stram() 获取数组流

    // 3. 通过Stream类中的静态方法of()

    // 4. 创建无限流(迭代、生成)

       

         /*
         * 创建流对象
         */
        // 1. 可以通过 Collection系列集合框架 提供  xxx.stream() 或者parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
        // 2. 通过Arrays 中的静态方法stram() 获取数组流
        Employee[] emps = new Employee[5];
        Stream<Employee> stream2 =  Arrays.stream(emps);
        // 3. 通过Stream类中的静态方法of()
        Stream<String> stream3 =  Stream.of("aa","bb","cc");
        // 4. 创建无限流(迭代、生成)
        //迭代
        Stream<Integer> stream4 =  Stream.iterate(0, x-> x+2);
        stream4.limit(4).forEach(System.out::println);
        
        //生成
        Stream.generate(()->Math.random())
        .limit(4)
        .forEach(System.out::println);

2.中间操作(多个中间操作可以连接起来形成一个流水线,只有流水线上有触发终止操作的情况,否则中间操作不会执行任何的处理,终止操作时会一次性全部处理,也称“惰性求值”)

常用的一些中间操作:

筛选与切片

    filter---接收 Lambda,从流中排除某些元素

    limit---截断流,使其元素不超过某个指定数量

    skip(n) --- 跳过元素,返回一个扔掉前n 个元素的流 ,若元素不足n 个,则返回一个空流,与limit(n)互补

    distinct--- 筛选,通过流所生成元素的hashCode() 和 equals() 去除重复元素

 映射

      map--接收Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。

      flatMap--接收一个函数作为参数,将该中的每一个值都换成另一个流,然后把所有流连接成一个流

排序

     sorted() -- 自然排序(Comparable)

     sorted(Comparator com) -- 自定义排序(Comparator)


// filter

//  添加公司员工
    List<Employee> list = Arrays.asList(
        new Employee("zhangsan", 33, 8888),
        new Employee("zhangsan2", 35, 18888),
        new Employee("zhangsan3", 37, 28888),
        new Employee("zhangsan4", 43, 34888),
        new Employee("zhangsan5", 53, 88888)
            );
    
    // 属于内部迭代  由Stream API 完成
    @Test
    public void test() {
        //中间操作,不会执行
        Stream<Employee> stream = list.stream()
                .filter(e -> {
                    System.out.println("Stream  中间操作");
                    return e.getAge() > 36;
                });
        // 惰性求值
        stream.forEach(System.out::println);
    }
    // 外部迭代
    @Test
    public void test2() {
        Iterator<Employee> it = list.iterator();
        
        while(it.hasNext()) {
            Employee e = it.next();
            if(e.getAge() > 36) {
                System.out.println(e);
            }
        }
    }


// limit

@Test
    public void test3() {
        list.stream()
        .filter(e -> {
            System.out.println("短路"); //&&  ||
            return e.getAge() > 36;
        })
        .limit(2)
        .forEach(System.out::println);
    }
    
//skip

@Test
    public void test4() {
        list.stream()
        .filter(e -> e.getSalary() > 5000)
        .skip(2)
        .forEach(System.out::println);
    }
// distinct 通过流所生成元素的hashCode() 和 equals() 去除重复元素

@Test
    public void test4() {
        list.stream()
        .filter(e -> e.getSalary() > 5000)
        .skip(2)
        .distinct()
        .forEach(System.out::println);
    }
// map

@Test
    public void test5() {
        List<String> list =  Arrays.asList("aa","bb","cc","ddd");
        list.stream()
            .map(str-> str.toUpperCase())
            .forEach(System.out::println);
        
        System.out.println("-----------------");
        
        employee.stream()
                .map(Employee::getName)
                .forEach(System.out::println);
                
    }

AA
BB
CC
DDD
-----------------
zhangsan
zhangsan2
zhangsan3
zhangsan4
zhangsan6
zhangsan5
zhangsan5
// flatMap

    // 方式1
        Stream<Stream<Character>> stream =  list.stream()
            .map(LambdaStream::filterCharacter);   //[a,b,c,[d,e]] 相当于集合中add()方法
        
        stream.forEach(sm ->  sm.forEach(System.out::println));
        
        System.out.println("-----------------");
        // 方式2
        Stream<Character> stream2 =  list.stream()
        .flatMap(LambdaStream::filterCharacter);   //[a,b,c,d,e] 相当于集合中addAll()方法
        
        stream2.forEach(System.out::println);
// sorted

/*
     * 排序
     * sorted() -- 自然排序(Comparable)
     * sorted(Comparator com) -- 自定义排序(Comparator)
     */
    @Test
    public void test6() {
        List<String> list =  Arrays.asList("aa","dd","bb","1");
        list.stream()
        .sorted()
        .forEach(System.out::println);
        
        System.out.println("--------------------------");
        
        employee.stream()
        .sorted((e1,e2) ->{
                if(e1.getAge().equals(e2.getAge()))
                    return  e1.getName().compareTo(e2.getName());
                else
                    return  e1.getAge().compareTo(e2.getAge());
            }).forEach(System.out::println);
    }

//
1
aa
bb
dd
--------------------------
Employee [name=zhangsan, age=33, salary=8888]
Employee [name=zhangsan2, age=35, salary=18888]
Employee [name=zhangsan3, age=37, salary=28888]
Employee [name=zhangsan4, age=43, salary=34888]
Employee [name=zhangsan5, age=53, salary=88888]
Employee [name=zhangsan5, age=53, salary=88888]
Employee [name=zhangsan6, age=53, salary=88888]

 

3.终止操作  (可以像sql 一样 优雅编程 )

    查找与匹配

                 *  allMatch --  检查是否匹配所有元素

                 *  anyMatch --  检查是否至少匹配一个元素

                 *  noneMatch -- 检查是否没有匹配所有元素

                 *  findFrist -- 返回第一个元素

                 *  findAny -- 返回当前流中的任意元素

                 *  count -- 返回流中元素总个数

                 *  max -- 返回流中最大值

                 *  min -- 返回流中最小值

     归约

             * reduce(T identity,BinaryOpertor) /  reduce(BinaryOperator) -- 可以将流中元素反复结合起来,得到一个值

                            "map- reduce" 模式  两个结合使用

    收集 

                collect -- 将流转换为其他流。接收一个Collector 接口的实现,用于给Stream 中元素做汇总的方法   

                提取信息聚合 求最大值、最小值、和... ;  

                分组、多级分组、汇总统计、提取信息  连接成字符串



/*
     *  查找与匹配
     *  allMatch --  检查是否匹配所有元素
     *  anyMatch --  检查是否至少匹配一个元素
     *  noneMatch -- 检查是否没有匹配所有元素
     *  findFrist -- 返回第一个元素
     *  findAny -- 返回当前流中的任意元素
     *  count -- 返回流中元素总个数
     *  max -- 返回流中最大值
     *  min -- 返回流中最小值
     */
    @Test
    public void test2() {
        long count = employee.stream().count();
        System.out.println(count);
        
        Optional<Employee> max =  employee.stream()
                .max((e1,e2) ->  Integer.compare(e1.getSalary(),e1.getSalary()));
        System.out.println(max.get());
        
        Optional<Integer> min =  employee.stream()
                .map(Employee::getSalary)
                .min(Integer::compare);
        System.out.println(min.get());
    }
    @Test
    public void test1() {
        boolean b1 = employee.stream()
                .allMatch((e) ->  e.getStatus().equals(Status.BUSY));
        System.out.println(b1); // false
        
        boolean b2 = employee.stream()
                .anyMatch((e) ->  e.getStatus().equals(Status.FREE));
        System.out.println(b2); // true
        
        boolean b3 = employee.stream()
                .noneMatch((e) ->  e.getStatus().equals(Status.VOCATION));
        System.out.println(b3); // false
        
        Optional<Employee> op =  employee.stream()
                .sorted((e1,e2) ->  -Integer.compare(e1.getSalary(),  e2.getSalary()))
                .findFirst(); // 有可能空指针  所以 java8  封装到Optional 中
        System.out.println(op.get());
        
        Optional<Employee> op2 =  employee.parallelStream()  // stream() 依次执行   parallelStream  并行同时执行
                .filter(e ->  e.getStatus().equals(Status.FREE)) //  parallelStream 由于并行 所以结果不唯一 随机
                .findAny();
        System.out.println(op2.get());
    }


collect -- 将流转换为其他流。接收一个Collector 接口的实现,用于给Stream 中元素做汇总的方法

/*
     * 收集
     *  collect -- 将流转换为其他流。接收一个Collector 接口的实现,用于给Stream 中元素做汇总的方法
     */
    @Test
    public void test4() {
        List<String> list = employee.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("------------------------");
        
        Set<Status> set = employee.stream()
            .map(Employee::getStatus)
            .collect(Collectors.toSet());
        set.forEach(System.out::println);
        
        System.out.println("------------------------");
        
        HashSet<Status> hashset =  employee.stream()
                .map(Employee::getStatus)
                .collect(Collectors.toCollection(HashSet::new));
        
        System.out.println(hashset); //[BUSY,  VOCATION, FREE]
        
        
        System.out.println("------------------------");
        // 总数
        Long count = employee.stream()
                .collect(Collectors.counting());
        System.out.println(count); // 7
        
        // 平均值
         Double avg = employee.stream()
                .collect(Collectors.averagingInt(Employee::getSalary));
        System.out.println(avg);
        
        // 最大值
        Optional<Employee> op =  employee.stream()
                .collect(Collectors.maxBy((e1,e2) ->  Double.compare(e1.getSalary(),  e2.getSalary())));
        System.out.println(op.get());
        
        // 最小值
        Optional<Integer> op2 =  employee.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Integer::compare));
        System.out.println(op2.get());
    }
    


// 多级分组
    @Test
    public void test6() {
        Map<Status, Map<String, List<Employee>>>  map = employee.stream()
                .collect(Collectors.groupingBy(Employee::getStatus,
                        Collectors.groupingBy(e  -> {
                            if(e.getAge() <=35)  return "青年";
                            else if (e.getAge()  <=50 ) return "中年";
                            else return "老年";
                        })));
        System.out.println(map);
        //{VOCATION={中年=[Employee  [name=zhangsan3, age=37, salary=28888,  status=VOCATION]]}, FREE={青年=[Employee  [name=zhangsan, age=33, salary=8888,  status=FREE]], 中年=[Employee [name=zhangsan4,  age=43, salary=34888, status=FREE]]}, BUSY={青年=[Employee [name=zhangsan2, age=35,  salary=18888, status=BUSY]]}}
    }
    // 分组
    @Test
    public void test5() {
        Map<Status, List<Employee>> map =  employee.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
        //{BUSY=[Employee [name=zhangsan2,  age=35, salary=18888, status=BUSY]],  FREE=[Employee [name=zhangsan, age=33,  salary=8888, status=FREE], Employee  [name=zhangsan4, age=43, salary=34888,  status=FREE]], VOCATION=[Employee  [name=zhangsan3, age=37, salary=28888,  status=VOCATION]]}
    }


//  添加公司员工
    List<Employee> employee = Arrays.asList(
        new Employee("zhangsan", 33,  8888,Status.FREE),
        new Employee("zhangsan2", 35,  18888,Status.BUSY),
        new Employee("zhangsan3", 37,  28888,Status.VOCATION),
        new Employee("zhangsan4", 43,  34888,Status.FREE)
    );
    
    /*
     * 收集
     *  collect -- 将流转换为其他流。接收一个Collector 接口的实现,用于给Stream 中元素做汇总的方法
     */
    // 提取信息  连接成字符串
    @Test
    public void test9() {
        String c = employee.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",",">>>","<<<"));
        System.out.println(c);
    }
    //汇总  统计
    @Test
    public void test8() {
        IntSummaryStatistics collect =  employee.stream()
                .collect(Collectors.summarizingInt(Employee::getSalary));
        System.out.println(collect.getAverage());
        System.out.println(collect.getMax());
    }
    // 分区
    @Test
    public void test7() {
        Map<Boolean, List<Employee>> map =  employee.stream()
                .collect(Collectors.partitioningBy(e ->  e.getSalary() > 10000));
        System.out.println(map);//{false=[Employee  [name=zhangsan, age=33, salary=8888,  status=FREE]], true=[Employee [name=zhangsan2,  age=35, salary=18888, status=BUSY], Employee  [name=zhangsan3, age=37, salary=28888,  status=VOCATION], Employee [name=zhangsan4,  age=43, salary=34888, status=FREE]]}
    }
    // 多级分组
    @Test
    public void test6() {
        Map<Status, Map<String, List<Employee>>>  map = employee.stream()
                .collect(Collectors.groupingBy(Employee::getStatus,
                        Collectors.groupingBy(e  -> {
                            if(e.getAge() <=35)  return "青年";
                            else if (e.getAge()  <=50 ) return "中年";
                            else return "老年";
                        })));
        System.out.println(map);
        //{VOCATION={中年=[Employee  [name=zhangsan3, age=37, salary=28888,  status=VOCATION]]}, FREE={青年=[Employee  [name=zhangsan, age=33, salary=8888,  status=FREE]], 中年=[Employee [name=zhangsan4,  age=43, salary=34888, status=FREE]]}, BUSY={青年=[Employee [name=zhangsan2, age=35,  salary=18888, status=BUSY]]}}
    }
    // 分组
    @Test
    public void test5() {
        Map<Status, List<Employee>> map =  employee.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
        //{BUSY=[Employee [name=zhangsan2,  age=35, salary=18888, status=BUSY]],  FREE=[Employee [name=zhangsan, age=33,  salary=8888, status=FREE], Employee  [name=zhangsan4, age=43, salary=34888,  status=FREE]], VOCATION=[Employee  [name=zhangsan3, age=37, salary=28888,  status=VOCATION]]}
    }
    @Test
    public void test4() {
        List<String> list = employee.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("------------------------");
        
        Set<Status> set = employee.stream()
            .map(Employee::getStatus)
            .collect(Collectors.toSet());
        set.forEach(System.out::println);
        
        System.out.println("------------------------");
        
        HashSet<Status> hashset =  employee.stream()
                .map(Employee::getStatus)
                .collect(Collectors.toCollection(HashSet::new));
        
        System.out.println(hashset); //[BUSY,  VOCATION, FREE]
        
        
        System.out.println("------------------------");
        // 总数
        Long count = employee.stream()
                .collect(Collectors.counting());
        System.out.println(count); // 7
        
        // 平均值
         Double avg = employee.stream()
                .collect(Collectors.averagingInt(Employee::getSalary));
        System.out.println(avg);
        
        // 最大值
        Optional<Employee> op =  employee.stream()
                .collect(Collectors.maxBy((e1,e2) ->  Double.compare(e1.getSalary(),  e2.getSalary())));
        System.out.println(op.get());
        
        // 最小值
        Optional<Integer> op2 =  employee.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Integer::compare));
        System.out.println(op2.get());
    }
    

 

/应用场景

1.用 Comparator 来排序

2.用 Runnable 执行代码块

3.GUI 事件处理

 

未完待续.....

共同进步,共同学习

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值