java8 stream流各种语法

优雅的将一个对象的集合转化成另一个对象的集合

List<OrderDetail> orderDetailList = orderDetailService.listOrderDetails();
List<CartDTO> cartDTOList = orderDetailList.stream()
                .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
                .collect(Collectors.toList());

交集 (list1 + list2)

List<T> intersect = list1.stream()
                         .filter(list2::contains)
                         .collect(Collectors.toList());

差集
 

//(list1 - list2)
List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList());

//(list2 - list1)
List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(toList());

并集

//使用并行流
List<String> listAll = list1.parallelStream().collect(toList());
List<String> listAll2 = list2.parallelStream().collect(toList());
listAll.addAll(listAll2);

去重并集
 

List<String> listAllDistinct = listAll.stream()
.distinct().collect(toList());


从List中过滤出一个元素

User match = users.stream()
.filter((user) -> user.getId() == 1).findAny().get();

Map集合转 List

List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey()))
        .map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());
        
List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue)).map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());

List<Person> list = map.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());

Collectors toList

streamArr.collect(Collectors.toList());
List<Integer> collectList = Stream.of(1, 2, 3, 4)
        .collect(Collectors.toList());
System.out.println("collectList: " + collectList);
// 打印结果 collectList: [1, 2, 3, 4]

Collectors toMap

map value 为对象 student
Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, student -> student));
// 遍历打印结果
map.forEach((key, value) -> {
    System.out.println("key: " + key + "    value: " + value);
});
map value 为对象中的属性
Map<Integer, String> map = list.stream().collect(Collectors.toMap(Student::getId, Student::getName));
map.forEach((key, value) -> {
    System.out.println("key: " + key + "    value: " + value);
});

List集合转 Map

/*使用Collectors.toMap形式*/
Map result = peopleList.stream().collect(Collectors.toMap(p -> p.name, p -> p.age, (k1, k2) -> k1));
//其中Collectors.toMap方法的第三个参数为键值重复处理策略,如果不传入第三个参数,当有相同的键时,会抛出一个IlleageStateException。
//或者
Map<Integer, String> result1 = list.stream().collect(Collectors.toMap(Hosting::getId, Hosting::getName));
//List<People> -> Map<String,Object>
List<People> peopleList = new ArrayList<>();
peopleList.add(new People("test1", "111"));
peopleList.add(new People("test2", "222"));
Map result = peopleList.stream().collect(HashMap::new,(map,p)->map.put(p.name,p.age),Map::putAll);

List 转 Map<Integer,Apple>

/**
 * List<Apple> -> Map<Integer,Apple>
 * 需要注意的是:
 * toMap 如果集合对象有重复的key,会报错Duplicate key ....
 *  apple1,apple12的id都为1。
 *  可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
 */
Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1, k2) -> k1));

List 转 List<Map<String,Object>>

List<Map<String,Object>> personToMap = peopleList.stream().map((p) -> {
    Map<String, Object> map = new HashMap<>();
    map.put("name", p.name);
    map.put("age", p.age);
    return map;
}).collect(Collectors.toList());
//或者
List<Map<String,Object>> personToMap = peopleList.stream().collect(ArrayList::new, (list, p) -> {
   Map<String, Object> map = new HashMap<>();
    map.put("name", p.name);
    map.put("age", p.age);
    list.add(map);
}, List::addAll);


字典查询和数据转换 toMap时,如果value为null,会报空指针异常

解决办法一:

Map<String, List<Dict>> resultMaps = Arrays.stream(dictTypes)
.collect(Collectors.toMap(i -> i, i -> Optional.ofNullable(dictMap.get(i)).orElse(new ArrayList<>()), (k1, k2) -> k2));


解决办法二:

Map<String, List<Dict>> resultMaps = Arrays.stream(dictTypes)
.filter(i -> dictMap.get(i) != null).collect(Collectors.toMap(i -> i, dictMap::get, (k1, k2) -> k2));


解决办法三:

Map<String, String> memberMap = list.stream().collect(HashMap::new, (m,v)->
    m.put(v.getId(), v.getImgPath()),HashMap::putAll);
System.out.println(memberMap);


解决办法四:

Map<String, String> memberMap = new HashMap<>();
list.forEach((answer) -> memberMap.put(answer.getId(), answer.getImgPath()));
System.out.println(memberMap);

Map<String, String> memberMap = new HashMap<>();
for (Member member : list) {
    memberMap.put(member.getId(), member.getImgPath());
}

假设有一个User实体类,有方法getId(),getName(),getAge()等方法,现在想要将User类型的流收集到一个Map中,示例如下:

Stream<User> userStream = Stream.of(new User(0, "张三", 18), new User(1, "张四", 19), new User(2, "张五", 19), new User(3, "老张", 50));

Map<Integer, User> userMap = userSteam.collect(Collectors.toMap(User::getId, item -> item));

假设要得到按年龄分组的Map<Integer,List>,可以按这样写:

Map<Integer, List<User>> ageMap = userStream.collect(Collectors.toMap(User::getAge, Collections::singletonList, (a, b) -> {
            List<User> resultList = new ArrayList<>(a);
            resultList.addAll(b);
            return resultList;
        }));

Map<Integer, String> map = persons
    .stream()
    .collect(Collectors.toMap(
        p -> p.age,
        p -> p.name,
        (name1, name2) -> name1 + ";" + name2));

System.out.println(map);
// {18=Max, 23=Peter;Pamela, 12=David}

Map 转 另一个Map

//示例1 Map<String, List<String>> 转 Map<String,User>
Map<String,List<String>> map = new HashMap<>();
map.put("java", Arrays.asList("1.7", "1.8"));
map.entrySet().stream();

@Getter
@Setter
@AllArgsConstructor
public static class User{
    private List<String> versions;
}

Map<String, User> collect = map.entrySet().stream()
                .collect(Collectors.toMap(
                        item -> item.getKey(),
                        item -> new User(item.getValue())));

//示例2 Map<String,Integer>  转 Map<String,Double>
Map<String, Integer> pointsByName = new HashMap<>();
Map<String, Integer> maxPointsByName = new HashMap<>();

Map<String, Double> gradesByName = pointsByName.entrySet().stream()
        .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
                entry.getKey(), ((double) entry.getValue() /
                        maxPointsByName.get(entry.getKey())) * 100d))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

List<String> 转String

//java8 String.join 方式  
List<String> webs = Arrays.asList("voidcc.com", "voidmvn.com", "voidtool.com");
//webs 必须是List<String>
String allwebs = String.join(",", webs);
System.out.println(allwebs);

//stream
List<String> webs = Arrays.asList("voidcc.com", "voidmvn.com", "voidtool.com");
String allwebs = webs.stream().collect(Collectors.joining(","));
System.out.println(allwebs);

Collectors toSet

Set<String> result = Stream.of("aa", "bb", "cc", "aa").collect(HashSet::new, HashSet::add, HashSet::addAll);
//Collectors类中已经预定义好了toList,toSet,toMap,toCollection等方便使用的方法,所以以上代码还可以简化如下:
Set<String> result2 = Stream.of("aa", "bb", "cc", "aa").collect(Collectors.toSet());

Set<Integer> collectSet = Stream.of(1, 2, 3, 4).collect(Collectors.toSet());
System.out.println("collectSet: " + collectSet);
// 打印结果 collectSet: [1, 2, 3, 4]

Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// collect toString
String str = stream.collect(Collectors.joining()).toString();

排序

//按照自然顺序进行排序 如果要自定义排序sorted 传入自定义的 Comparator
list.stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

//对象排序比较 请重写对象的equals()和hashCode()方法
list.sorted((a, b) -> b.compareTo(a))

Collections.sort(names, (a, b) -> b.compareTo(a));

比较

Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0

Collectors groupingBy 分组

Map<Integer, List<User>> ageMap2 = userStream
.collect(Collectors.groupingBy(User::getAge));

对集合按照多个属性分组
将多个字段拼接成一个新字段,然后再使用groupBy分组

Map<String, List<EntryDeliveryDetailywk>> detailmap = details.stream()
.collect(Collectors.groupingBy(this::fetchGroupKey));

private String fetchGroupKey(EntryDeliveryDetailywk detail){
        return detail.getSkuId().toString()
        + detail.getItemsName()
        + detail.getWarehouseId().toString()   
        + detail.getSupplierId().toString();
    }


groupingBy 分组后操作

//Collectors中还提供了一些对分组后的元素进行downStream处理的方法:
//counting方法返回所收集元素的总数;
//summing方法会对元素求和;
//maxBy和minBy会接受一个比较器,求最大值,最小值;
//mapping函数会应用到downstream结果上,并需要和其他函数配合使用;

Map<Integer, Long> sexCount = userStream.collect(Collectors.groupingBy(User::getSex,Collectors.counting()));

Map<Integer, Integer> ageCount = userStream.collect(Collectors.groupingBy(User::getSex,Collectors.summingInt(User::getAge)));

Map<Integer, Optional<User>> ageMax =  userStream.collect(Collectors.groupingBy(User::getSex,Collectors.maxBy(Comparator.comparing(User::getAge))));

Map<Integer, List<String>> nameMap =  userStream.collect(Collectors.groupingBy(User::getSex,Collectors.mapping(User::getName,Collectors.toList())));

groupingBy 根据年龄来分组:

Map<Integer, List> peopleByAge = peoples.stream()
.filter(p -> p.age > 12).collect(Collectors.groupingBy(p -> p.age, Collectors.toList()));

groupingBy 根据年龄分组,年龄对应的键值List存储的为Person的姓名:

Map<Integer, List> peopleByAge = people.stream()
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p.name, Collectors.toList())));
//mapping即为对各组进行投影操作,和Stream的map方法基本一致。

groupingBy 根据姓名分组,获取每个姓名下人的年龄总和:

Map sumAgeByName = peoples.stream().collect(Collectors.groupingBy(p -> p.name, Collectors.reducing(0, (Person p) -> p.age, Integer::sum)));
/* 或者使用summingInt方法 */
sumAgeByName = peoples.stream().collect(Collectors.groupingBy(p -> p.name, Collectors.summingInt((Person p) -> p.age)));

groupingBy Boolean分组:

Map<Boolean, List<Integer>> collectGroup = Stream.of(1, 2, 3, 4)
            .collect(Collectors.groupingBy(it -> it > 3));
System.out.println("collectGroup : " + collectGroup);
// 打印结果
// collectGroup : {false=[1, 2, 3], true=[4]}

groupingBy 按年龄分组

Map<Integer, List<Person>> personsByAge = persons.stream().collect(Collectors.groupingBy(p -> p.age));
personsByAge.forEach((age, p) -> System.out.format("age %s: %s\n", age, p));
// age 18: [Max]
// age 23: [Peter, Pamela]
// age 12: [David]

Map.merge() 类似于分组之后sum

Map<String, Integer> studentScoreMap2 = new HashMap<>();
        studentScoreList.forEach(studentScore -> studentScoreMap2.merge(
          studentScore.getStuName(),
          studentScore.getScore(),
          Integer::sum));

Collectors partitioningBy
Collectors中还提供了partitioningBy方法,接受一个Predicate函数,该函数返回boolean值,用于将内容分为两组。假设User实体中包含性别信息getSex(),可以按如下写法将userStream按性别分组:

Map<Boolean, List<User>> sexMap = userStream
.collect(Collectors.partitioningBy(item -> item.getSex() > 0));

集合对象通过某个属性去重

List<User> collect1 = list.stream().
collect(Collectors.collectingAndThen
((Collectors.toCollection((() -> new TreeSet<>(Comparator.comparing(User::getEmpCode))))), ArrayList::new));

Collectors提供了一系列用于数据统计的静态方法:

计数: count

平均值: averagingInt、 averagingLong、 averagingDouble

最值: maxBy、 minBy

求和: summingInt、 summingLong、 summingDouble

统计以上所有: summarizingInt、 summarizingLong、 summarizingDouble
 

/**
 * 统计员工人数、平均工资、工资总额、最高工资
 */
private static void test01(){
    //统计员工人数
    Long count = personList.stream().collect(Collectors.counting());
    //求平均工资
    Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
    //求最高工资
    Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
    //求工资之和
    Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
    //一次性统计所有信息
    DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
    System.out.println("统计员工人数:"+count);
    System.out.println("求平均工资:"+average);
    System.out.println("求最高工资:"+max);
    System.out.println("求工资之和:"+sum);
    System.out.println("一次性统计所有信息:"+collect);
}

Reduce:1.求所有员工的工资之和和最高工资

/*
 * 求所有员工的工资之和和最高工资
 */
private static void test14() {
    initPerson();
    Optional<Integer> reduce = personList.stream().map(Person :: getSalary).reduce(Integer::sum);
    Optional<Integer> reduce2 = personList.stream().map(Person :: getSalary).reduce(Integer::max);
    System.out.println("工资之和:"+reduce);
    System.out.println("最高工资:"+reduce2);
}

2.求Integer集合的元素之和、乘积和最大值

/**
 * 求Integer集合的元素之和、乘积和最大值
 *
 */
private static void test13() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    //求和
    Optional<Integer> reduce = list.stream().reduce((x,y) -> x+ y);
    System.out.println("求和:"+reduce);
    //求积
    Optional<Integer> reduce2 = list.stream().reduce((x,y) -> x * y);
    System.out.println("求积:"+reduce2);
    //求最大值
    Optional<Integer> reduce3 = list.stream().reduce((x,y) -> x>y?x:y);
    System.out.println("求最大值:"+reduce3);
}

1、遍历/匹配(foreach/find/match)

// import已省略,请自行添加,后面代码亦是
 
public class StreamTest {
  public static void main(String[] args) {
        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
 
        // 遍历输出符合条件的元素
        list.stream().filter(x -> x > 6).forEach(System.out::println);
        // 匹配第一个
        Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
        // 匹配任意(适用于并行流)
        Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
        // 是否包含符合特定条件的元素
        boolean anyMatch = list.stream().anyMatch(x -> x < 6);
        System.out.println("匹配第一个值:" + findFirst.get());
        System.out.println("匹配任意一个值:" + findAny.get());
        System.out.println("是否存在大于6的值:" + anyMatch);
    }
}

2、聚合max、min、count

(1)获取String集合中最长的元素

/**
 * 获取String集合中最长的元素
 * @思路
 * List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
 * String max = "";
 * int length = 0;
 * int tempLength = 0;
 * for(String str : list) {
 *     tempLength = str.length();
 *     if(tempLength > length) {
 *         length  = str.length();
 *         max = str;
 *      }
 * }
 * @return zhangsan
 */
private static void test02() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "sunliu");
    Comparator<? super String> comparator = Comparator.comparing(String::length);
    Optional<String> max = list.stream().max(comparator);
    System.out.println(max);
}

(2)获取Integer集合中的最大值

//获取Integer集合中的最大值
private static void test05() {
    List<Integer> list = Arrays.asList(1, 17, 27, 7);
    Optional<Integer> max = list.stream().max(Integer::compareTo);
    // 自定义排序
    Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1.compareTo(o2);
        }
    });
    System.out.println(max2);
}

(3)获取员工中年龄最大的人

        

//获取员工中年龄最大的人
private static void test06() {
    initPerson();
    Comparator<? super Person> comparator = Comparator.comparingInt(Person::getAge);
    Optional<Person> max = personList.stream().max(comparator);
    System.out.println(max);
}

4)计算integer集合中大于10的元素的个数

 

3、排序sorted

private static void test04(){
    // 按工资升序排序(自然排序)
    List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
            .collect(Collectors.toList());
    // 按工资倒序排序
    List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
            .map(Person::getName).collect(Collectors.toList());
    // 先按工资再按年龄升序排序
    List<String> newList3 = personList.stream()
            .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
            .collect(Collectors.toList());
    // 先按工资再按年龄自定义排序(降序)
    List<String> newList4 = personList.stream().sorted((p1, p2) -> {
        if (p1.getSalary() == p2.getSalary()) {
            return p2.getAge() - p1.getAge();
        } else {
            return p2.getSalary() - p1.getSalary();
        }
    }).map(Person::getName).collect(Collectors.toList());
 
    System.out.println("按工资升序排序:" + newList);
    System.out.println("按工资降序排序:" + newList2);
    System.out.println("先按工资再按年龄升序排序:" + newList3);
    System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
}

4、提取/组合

private static void test05(){
    String[] arr1 = { "a", "b", "c", "d" };
    String[] arr2 = { "d", "e", "f", "g" };
    Stream<String> stream1 = Stream.of(arr1);
    Stream<String> stream2 = Stream.of(arr2);
    // concat:合并两个流 distinct:去重
    List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
    // limit:限制从流中获得前n个数据
    List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
    // skip:跳过前n个数据
    List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
 
    System.out.println("流合并:" + newList);
    System.out.println("limit:" + collect);
    System.out.println("skip:" + collect2);
}

可以看到Java8的分组功能相当强大,当然你还可以完成更复杂的功能。另外Collectors中还存在一个类似groupingBy的方法:partitioningBy,它们的区别是partitioningBy为键值为Boolean类型的groupingBy,这种情况下它比groupingBy更有效率。
partitioningBy 将数字的Stream分解成奇数集合和偶数集合。

Map<Boolean, List<Integer>> collectParti = Stream.of(1, 2, 3, 4)
            .collect(Collectors.partitioningBy(it -> it % 2 == 0));
System.out.println("collectParti : " + collectParti);
// 打印结果
// collectParti : {false=[1, 3], true=[2, 4]}

Collectors joining
Collectors.joining 收集Stream中的值,该方法可以方便地将Stream得到一个字符串。joining函数接受三个参数,分别表示允(用以分隔元素)、前缀和后缀:

String names = peoples.stream().map(p->p.name).collect(Collectors.joining(","))

String strJoin = Stream.of("1", "2", "3", "4")
        .collect(Collectors.joining(",", "[", "]"));
System.out.println("strJoin: " + strJoin);
// 打印结果
// strJoin: [1,2,3,4]

//字符串连接
String phrase = persons
    .stream()
    .filter(p -> p.age >= 18)
    .map(p -> p.name)
    .collect(Collectors.joining(" and ", "In Germany ", " are of legal age."));
System.out.println(phrase);
// In Germany Max and Peter and Pamela are of legal age.

组合 Collectors:

Map<Boolean, Long> partiCount = Stream.of(1, 2, 3, 4)
        .collect(Collectors.partitioningBy(it -> it.intValue() % 2 == 0,
                Collectors.counting()));
System.out.println("partiCount: " + partiCount);
// 打印结果
// partiCount: {false=2, true=2}

Collectors分别提供了求平均值averaging、总数couting、最小值minBy、最大值maxBy、求和suming等操作。但是假如你希望将流中结果聚合为一个总和、平均值、最大值、最小值,那么Collectors.summarizing(Int/Long/Double)就是为你准备的,它可以一次行获取前面的所有结果,其返回值为(Int/Long/Double)SummaryStatistics。

DoubleSummaryStatistics dss = people.collect(Collectors.summarizingDouble((Person p)->p.age));
double average=dss.getAverage();
double max=dss.getMax();
double min=dss.getMin();
double sum=dss.getSum();
double count=dss.getCount();

IntSummaryStatistics ageSummary = persons
        .stream()
        .collect(Collectors.summarizingInt(p -> p.age));

System.out.println(ageSummary);
// IntSummaryStatistics{count=4, sum=76, min=12, average=19.000000, max=23}

使用collect可以将Stream转换成值。maxBy和minBy允许用户按照某个特定的顺序生成一个值。
averagingDouble:求平均值,Stream的元素类型为double
averagingInt:求平均值,Stream的元素类型为int
averagingLong:求平均值,Stream的元素类型为long
counting:Stream的元素个数
maxBy:在指定条件下的,Stream的最大元素
minBy:在指定条件下的,Stream的最小元素
reducing: reduce操作
summarizingDouble:统计Stream的数据(double)状态,其中包括count,min,max,sum和平均。
summarizingInt:统计Stream的数据(int)状态,其中包括count,min,max,sum和平均。
summarizingLong:统计Stream的数据(long)状态,其中包括count,min,max,sum和平均。
summingDouble:求和,Stream的元素类型为double
summingInt:求和,Stream的元素类型为int
summingLong:求和,Stream的元素类型为long

Optional<Integer> collectMaxBy = Stream.of(1, 2, 3, 4)
            .collect(Collectors.maxBy(Comparator.comparingInt(o -> o)));
System.out.println("collectMaxBy:" + collectMaxBy.get());
// 打印结果
// collectMaxBy:4

Collectors averagingInt
计算集合的平均年龄

Double averageAge = persons
    .stream()
    .collect(Collectors.averagingInt(p -> p.age));

System.out.println(averageAge);     // 19.0

自定义 Collector

Collector<Person, StringJoiner, String> personNameCollector =
    Collector.of(
        () -> new StringJoiner(" | "),          // supplier
        (j, p) -> j.add(p.name.toUpperCase()),  // accumulator
        (j1, j2) -> j1.merge(j2),               // combiner
        StringJoiner::toString);                // finisher

String names = persons
    .stream()
    .collect(personNameCollector);

System.out.println(names);  // MAX | PETER | PAMELA | DAVID

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值