Java.Stream和方法引用

Stream流

Stream流引入

Stream流不是I/O流,按照流水线处理方式来考虑代码中的思想。JDK1.8 之后,我们拥有了Lambda表达式,让代码的中心偏向解决实际问题,直到重点,可以提高效率。Stream流中使用了大量Lambda表达式,利用Lambda操作方式,提供开发效率。

传统遍历方式和Stream类处理方式对比

传统用ArrayList的遍历方式:

import java.util.ArrayList;
/**
* 操作集合处理集合
* 操作过程中创建了多个ArrayList,但是这些ArrayList都是过客,
* 不涉及到程序的核心,这里会导致资源的浪费。
* @author Anonymous 2020/3/12 9:56
*/
public class Demo2 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("宫保鸡丁");
		list.add("酱牛肉");
		list.add("羊肉串");
		list.add("烤羊排");
		list.add("羊肉汤");
		list.add("驴肉火烧");
		// 第一步: 对List进行过程,找出list中保存元素带有肉的,保存到另一个集合中
		ArrayList<String> list1 = new ArrayList<>();
		for (String s : list) {
			if (s.contains("肉")) {
				list1.add(s);
			}
		}
		// 第二步: 找出菜名长度==3的,保存到另一个集合中
		ArrayList<String> list2 = new ArrayList<>();
		for (String s : list1) {
			if (3 == s.length()) {
				list2.add(s);
			}
		}
		// 第三步:遍历展示对应的数据
		for (String s : list2) {
			System.out.println(s);
		}
	}
}

引入Stream流的处理方式:

import java.util.ArrayList;
/**
* 操作集合处理集合
* 采用Stream流方式
*
* @author Anonymous 2020/3/12 9:56
*/
public class Demo2 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("宫保鸡丁");
		list.add("酱牛肉");
		list.add("羊肉串");
		list.add("烤羊排");
		list.add("羊肉汤");
		list.add("驴肉火烧");
		/*
		采用Stream流方式来处理
		直观角度可以发现,这里Stream流处理方式可以简
		化代码逻辑,
		更侧重于操作的重点
		第一步: 对List进行过程,找出list中保存元素带
		有肉的,
		第二步: 找出菜名长度==3的
		第三步:遍历展示对应的数据
		*/
		list.stream().filter(s->s.contains("肉")).filter(s -> 3 == s.length())
		.forEach(s ->System.out.println(s));
	}
}

Stream流对应的思想

流水线:
原材料从头到尾只会占用一份空间,中间的过程中不会占用空间。最后生成一个结果。
在这里插入图片描述
在这里插入图片描述
Stream流有一些特征:

  1. 带有很多Stream流操作的方法, filter,limit, map,sorted,skip…这些方法大多是都会使用到函数式接口,有lambda表达式。
  2. 整个Stream流模型操作过程中,只有执行到count, foreach这些方法,操作真正的执行中的模型,如果不存在结果导向,中间的所有操作是无效的,这里得益于Lambda表达式的延后性。
  3. Stream流是存在一定的管道性 Pipelining 流水线。

获取Stream流

java.util.stream.Stream JDK1.8的新特征

1. 所有的 Collection<T> 集合都有对应的Stream();
2. 可以通过Stream类中的static Stream of()获取
static Stream<T> of(T... t);
static Stream<T> of(T t);
import java.util.*;
import java.util.stream.Stream;
/**
* Stream流获取方式
* 1. Collection集合
* 2. Map双边队列
* 3. 数组
*
* @author Anonymous 2020/3/12 11:16
*/
public class Demo1 {
	public static void main(String[] args) {
		// List接口获取对应的Stream流类对象
		List<String> list = new ArrayList<>();
		// 根据list保存元素的类型来约束对应的Stream流对象操作所需类型
		Stream<String> stream = list.stream();
		// 通过Set集合获取对应Stream流对象
		HashSet<String> set1 = new HashSet<>();
		Stream<String> stream1 = set1.stream();
		HashMap<String, String> map = new HashMap<>();
		// Map双边队列中所有键对应的Set集合
		Set<String> keySet = map.keySet();
		Stream<String> stream2 = keySet.stream();
		// Map双边队列中所有value对应的Collection集合
		Collection<String> values = map.values();
		Stream<String> stream3 = values.stream();
		// map中有一个方法,可以获取所有键值对类型的Set集合
		// Entry ==> 键值对,是Map接口的一个成员接口
		Set<Map.Entry<String, String>> entrySet = map.entrySet();
		// 获取Map键值对集合的Stream流对象
		Stream<Map.Entry<String, String>> stream4 = entrySet.stream();
		// 使用不定长参数获取对应的Stream流对象
		// Stream类内的静态方法of,更多的是用于数组操作提供Stream流对象
		Stream<String> stringStream =
		Stream.of("酱牛肉", "羊肉抓饭", "羊肉汤", "羊蝎子");
		String[] arr = {"黄河大鲤鱼", "方中山胡辣汤", "萧记烩面", "蔡记蒸饺", "葛记焖饼"};
		Stream<String> arrStream = Stream.of(arr);
		// 不建议这样使用!!!
		ArrayList<String> list1 = new ArrayList<>();
		Stream<ArrayList<String>> list11 = Stream.of(list1);
	}
}

Stream常用方法

延迟方法:

返回值类型依然是Stream接口本身,并没有影响我们操作真正的资源,允许链式操作,

例如

filter(XXX).limit(XXX).sorted(XXX).

终结方法:

返回值类型不是Stream接口本身,要么处理数据,要么返回其他类型数据,并且不再支持Stream流对象链式操作,
count,foreach

foreach方法

void foreach(Consumer<? super T> action);
/*
终结方法:
需要一个Consumer接口进行操作处理,消耗一个数据
Consumer接口是一个【函数式接口】那就可以使用
Lambda表达式
Consumer接口中方法是
void accept(T t);
*/
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* Stream流foreach方法使用
*
* @author Anonymous 2020/3/12 11:39
*/
public class Demo1 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("蛋炒饭");
		list.add("虎皮青椒");
		list.add("手撕包菜");
		list.add("鲱鱼罐头");
		// 得到List对应的Stream流对象
		Stream<String> stream = list.stream();
		/*
		Stream<String> Stream流,这里操作的是String
		类型
		匿名内部类的匿名对象作为方法的参数,曾经
		多么厉害,现在是有点low
		*/
		stream.forEach(new Consumer<String>() {
			@Override
			public void accept(String s) {
				System.out.println(s);
			}
		});
		// 这里需要的参数是Consumer函数式接口,完成可以使用Lambda表达式完成
		stream.forEach(string -> System.out.println(string));
		// 我们在哪里见过??? 方法引用
		stream.forEach(System.out::println);
	}
}

filter方法

Stream<T> filter(Predicate<? super T> condition);
/*
filter是过滤方式,需要的参数是Predicate接口,
Predicate是一个函数式接口,可以直接使用Lambda表达运
行。
这里返回值类型是Stream类对象,是经过过滤之后的
Stream类型,可以进行链式操作
Predicate接口中需要实现的方法
boolean test(T t);
*/
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* Stream流对象filter方法演示
*
* @author Anonymous 2020/3/12 11:50
*/
public class Demo2 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("擀面皮");
		list.add("肉夹馍");
		list.add("冰峰");
		list.add("水盆羊肉");
		Stream<String> stringStream = list.stream().filter(s -> s.length() >= 3);
		stringStream.forEach(System.out::println);
		Stream<String> stringStream1 = stringStream.filter(s -> 4 == s.length());
		stringStream1.forEach(System.out::println);
		/*
		Exception in thread "main"
		java.lang.IllegalStateException: stream has
		already been operated upon or closed
		at java.util.stream.AbstractPipeline.
		<init>(AbstractPipeline.java:203)
		at
		java.util.stream.ReferencePipeline.<init>
		(ReferencePipeline.java:94)
		at
		java.util.stream.ReferencePipeline$StatelessOp.
		<init>(ReferencePipeline.java:618)
		at
		java.util.stream.ReferencePipeline$2.<init>
		(ReferencePipeline.java:163)
		at
		java.util.stream.ReferencePipeline.filter(Referen
		cePipeline.java:162)
		at
		com.qfedu.c_streamfunction.Demo2.main(Demo2.java:23)
		*/
	}
}

map方法

<R> Stream<R> map(Function<? super T, ? super R> fun);
/*
类型转换操作,得到的一个转换之后数据类型的Stream流对
象
这里需要的参数是Functtion函数式接口,
R apply(T t);
T类型的数据转换成R类型数据
*/
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* Stream流 map映射方法演示
*
* @author Anonymous 2020/3/12 14:39
*/
public class Demo3 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("1,骚磊,16");
		list.add("2,骚杰,66");
		list.add("3,老黑,46");
		list.add("4,老付,36");
		list.add("5,污云,56");
		list.add("6,帅栋,26");
		System.out.println(list);
		Stream<Person> personStream = list.stream().map(s -> {
			String[] split = s.split(",");
			Person person = new Person();
			person.setId(Integer.parseInt(split[0]));
			person.setName(split[1]);
			person.setAge(Integer.parseInt(split[2]));
			return person;
		});
		personStream.forEach(System.out::println);
	}
}

count方法

long count();
/*
返回当前Stream流对象中有多少个元素
类似有Collection接口下的size(). String的length();
【终结方法】
一旦执行Stream流对象被关闭
*/
import java.util.ArrayList;
/**
* Stream流对象 count方法演示【终结方法】
*
* @author Anonymous 2020/3/12 14:50
*/
public class Demo4 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("擀面皮");
		list.add("肉夹馍");
		list.add("冰峰");
		list.add("水盆羊肉");
		// 当前Stream流对象中有多少个元素,终结方法
		long count = list.stream().filter(s -> s.length() >= 3).count();
		System.out.println(count);
	}
}

limit方法

Stream<T> limit(long maxSize);
/*
对于当前Stream流对象操作的数据进行限制操作,限制个数
到maxSize
例如:
Stream流中保存的有10个元素,limit 5 ==> 前五个元
素
*/
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* Stream流对象 limit方法
*
* @author Anonymous 2020/3/12 15:03
*/
public class Demo5 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("红旗");
		list.add("领克");
		list.add("吉利");
		list.add("比亚迪");
		list.add("长安");
		list.add("五菱宏光");
		Stream<String> stream = list.stream();
		// @throws IllegalArgumentException if {@code maxSize} is negative
		stream.limit(5).forEach(System.out::println);
	}
}

skip方法

Stream<T> skip(long n);
/*
返回值依然是一个Stream流对象,这里跳过当前Stream流对
象前n个元素
*/
import java.util.ArrayList;
/**
* Stream流对象 skip方法
*
* @author Anonymous 2020/3/12 15:10
*/
public class Demo6 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("陆巡");
		list.add("高R");
		list.add("RS7");
		list.add("s4");
		list.add("霸道");
		list.add("道奇");
		list.stream().skip(2).forEach(System.out::println);
	}
}

concat方法

static Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
/*
拼接两个Stream流对象,是一个静态方法,得到新的Stream
流对象
*/
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* Stream流 静态成员方法 concat方法
*
* @author Anonymous 2020/3/12 15:15
*/
public class Demo7 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("红旗");
		list.add("领克");
		list.add("吉利");
		list.add("比亚迪");
		list.add("长安");
		list.add("五菱宏光");
		ArrayList<String> list1 = new ArrayList<>();
		list1.add("陆巡");
		list1.add("高R");
		list1.add("RS7");
		list1.add("s4");
		list1.add("霸道");
		list1.add("道奇");
		// 获取到两个Stream流,其中保存的数据类型都是String类型
		Stream<String> stream = list.stream();
		Stream<String> stream1 = list1.stream();
		Stream<String> concat = Stream.concat(stream, stream1);
		concat.forEach(System.out::println);
	}
}

原始操作方式和Stream流方式对比

题目:

  1. 一个String类型的字符串集合,“1,骚磊,16”
  2. 过滤没有5的数据
  3. 跳过前三个数据
  4. 限制得到前5个数据
  5. 两个String类型集合字符串合并
  6. 转换成Person类型
  7. 展示数据

原始方式代码演示:

import java.util.ArrayList;
/**
* 采用原始的List集合方式操作
* 1. 一个String类型的字符串集合,"1,骚磊,16"
* 2. 过滤没有5的数据
* 3. 跳过前三个数据
* 4. 限制得到前5个数据
* 5. 两个String类型集合字符串合并
* 6. 转换成Person类型
* 7. 展示数据
*
* 太浪费资源,浪费时间!!!
* @author Anonymous 2020/3/12 15:22
*/
public class Demo8 {
	public static void main(String[] args) {
		// 1. 一个String类型的字符串集合,"1,骚磊,16"
		ArrayList<String> list1 = new ArrayList<>();
		list1.add("1,骚磊,15");
		list1.add("2,骚杰,65");
		list1.add("3,老黑,45");
		list1.add("4,老付,56");
		list1.add("5,污云,56");
		list1.add("6,帅栋,26");
		list1.add("7,帅栋,56");
		list1.add("8,帅栋,25");
		list1.add("9,帅栋,26");
		list1.add("10,帅栋,26");
		list1.add("11,帅栋,25");
		list1.add("12,帅栋,56");
		list1.add("13,帅栋,55");
		// 2. 过滤没有5的数据
		ArrayList<String> list2 = new ArrayList<>();
		for (String s : list1) {
			if (s.contains("5")) {
				list2.add(s);
			}
		}
		System.out.println(list2);
		// 3. 跳过前三个数据
		ArrayList<String> list3 = new ArrayList<>();
		for (int i = 3; i < list2.size(); i++) {
			list3.add(list2.get(i));
		}
		System.out.println(list3);
		// 4. 限制得到前5个数据
		ArrayList<String> list4 = new ArrayList<>();
		for (int i = 0; i < 5; i++) {
			list4.add(list3.get(i));
		}
		// 5. 两个String类型集合字符串合并
		ArrayList<String> list5 = new ArrayList<>();
		list5.add("1,骚磊,15");
		list5.add("2,骚杰,65");
		list5.add("3,老黑,45");
		list5.add("4,老付,56");
		list5.add("5,污云,56");
		list4.addAll(list5);
		// 6. 转换成Person类型
		ArrayList<Person> list6 = new ArrayList<>();
		for (String s : list4) {
			String[] split = s.split(",");
			Person person = new Person();
			person.setId(Integer.parseInt(split[0]));
			person.setName(split[1]);
			person.setAge(Integer.parseInt(split[2]));
			list6.add(person);
		}
		// 7. 展示数据
		for (Person person : list6) {
			System.out.println(person);
		}
	}
}

Stream流方式代码演示:

import java.util.ArrayList;
import java.util.stream.Stream;
/**
* 采用原始的Stream流对象思想方式操作
* 1. 一个String类型的字符串集合,"1,骚磊,16"
* 2. 过滤没有5的数据
* 3. 跳过前三个数据
* 4. 限制得到前5个数据
* 5. 两个String类型集合字符串合并
* 6. 转换成Person类型
* 7. 展示数据
* @author Anonymous 2020/3/12 15:29
*/
public class Demo9 {
	public static void main(String[] args) {
		ArrayList<String> list1 = new ArrayList<>();
		list1.add("1,骚磊,15");
		list1.add("2,骚杰,65");
		list1.add("3,老黑,45");
		list1.add("4,老付,56");
		list1.add("5,污云,56");
		list1.add("6,帅栋,26");
		list1.add("7,帅栋,56");
		list1.add("8,帅栋,25");
		list1.add("9,帅栋,26");
		list1.add("10,帅栋,26");
		list1.add("11,帅栋,25");
		list1.add("12,帅栋,56");
		list1.add("13,帅栋,55");
		ArrayList<String> list2 = new ArrayList<>();
		list2.add("1,骚磊,15");
		list2.add("2,骚杰,65");
		list2.add("3,老黑,45");
		list2.add("4,老付,56");
		list2.add("5,污云,56");
		list2.add("6,帅栋,26");
		list2.add("7,帅栋,56");
		Stream<String> stream = list1.stream();
		Stream<String> limit = stream.filter(s -> s.contains("5")).skip(3).limit(5);
		Stream.concat(limit, list2.stream()).map(s -> {
			String[] split = s.split(",");
			Person person = new Person();
			person.setId(Integer.parseInt(split[0]));
			person.setName(split[1]);
			person.setAge(Integer.parseInt(split[2]));
			return person;
		}).forEach(System.out::println);
	}
}

方法引用

Lambda冗余问题以及方法引用初识

/**
* 函数式接口
*
* @author Anonymous
*/
@FunctionalInterface
interface PrintMethod {
	void print(String str);
}
/**
* Lambda冗余问题
*
* @author Anonymous 2020/3/12 15:53
*/
public class Demo1 {
	public static void main(String[] args) {
		/*
		使用Lambda表达式来展示字符串
		IDEA有一个提示,这里可以继续优化
		目标:
		testPrint方法,需要将String str交给
		PrintMethod进行处理
		PrintMethod处理的方式是
		System.out.println
		PrintMethod是一个函数式接口,可以使用
		Lambda表达式完成代码
		但是貌似和这个接口,这里Lambda不够接近目
		标
		明确:
		1. 我要用System.out对象
		2. 需要使用println方法
		3. 需要处理的数据是明确的
		*/
		testPrint("郑州加油!!!", str -> System.out.println(str));
		// 利用方法引用来处理当前代码
		/*
		调用对象:
		System.out
		执行方法:
		println方法
		需要处理的数据(可推导,可省略)
		"中国加油!!!祖国万岁!!!"
		::
		Java中【方法引用】使用的运算符,标记
		*/
		testPrint("中国加油!!!祖国万岁!!!", System.out::println);
	}
	/**
	* 该方法是一个使用函数式接口作为方法参数的一个方
	法
	*
	* @param str String类型的字符串
	* @param pm PrintMethod函数式接口
	*/
	public static void testPrint(String str, PrintMethod pm) {
		pm.print(str);
	}
}

方法引用小要求

testPrint("郑州加油!!!", str -> System.out.println(str));

testPrint("郑州加油!!!", System.out::println);
  1. 明确对象
    对象 ==> 调用者
    类对象,类名,super,this,构造方法,数组构造方法
  2. 明确的执行方法
    该方法只有名字不需要显式出现参数
  3. 需要处理的数据
    【联想,推导,省略】
  4. :: 方法引用格式

通过类对象来执行方法引用

  1. 明确对象
    类对象
  2. 明确执行的方法
    自定义
  3. 处理的数据
    简单要求为String类型
/**
* 函数式接口
* 明确约束方法
* 方法类型是
* 参数是String类型参数
* 没有返回值
*/
@FunctionalInterface
public interface Printable {
	void method(String str);
}
/**
* 自定义类
*/
public class ObjectMethodReference {
	/**
	* ObjectMethodReference类内的【成员方法】
	* 1. 参数是String类型
	* 2. 没有返回值
	* @param str 参数
	*/
	public void print(String str) {
		System.out.println(str.toLowerCase());
	}
	/**
	* ObjectMethodReference类内的【成员方法】
	* 1. 参数是String类型
	* 2. 没有返回值
	* @param str 参数
	*/
	public void printSubstring(String str) {
		System.out.println(str.substring(3));
	}
	public void saolei() {
		System.out.println("无参数方法");
	}
}
/**
* 类对象使用方法引用展示
*
* @author Anonymous 2020/3/12 16:18
*/
public class Demo2 {
	public static void main(String[] args) {
		/*
		test方法需要使用一个Printable接口,执行对应
		的print方法
		这里需要引用ObjectMethodReference类对象对应
		的print方法,该方法有展示能力
		*/
		ObjectMethodReference obj = new ObjectMethodReference();
		/*
		执行的对象:
		ObjectMethodReference的类对象
		明确执行的方法:
		print方法
		执行的目标:
		"ABCDE" 可省略,可推导
		*/
		test(obj::printSubstring);
	}
	/**
	*
	* @param printable 函数式接口,约束的是方法类型
	*/
	public static void test(Printable printable) {
		printable.method("ABCDE");
	}
}

通过类名来执行方法引用

import java.util.List;
/**
* 函数式接口
*/
@FunctionalInterface
public interface PrintList {
	/**
	* 方法参数为List集合
	* 没有返回值
	* @param list List集合
	*/
	void print(List<?> list);
}
import java.util.List;
/**
* 通过列明调用的静态方法,演示类
*/
public class ClassMethodReference {
	/**
	* 该方法符合要求
	* 没有返回值
	* @param list list集合
	*/
	public static void showListInfo(List<?> list) {
		for (Object o : list) {
			System.out.println(o);
		}
	}
}
import java.util.ArrayList;
/**
* 通过类名来执行方法引用
*
* @author Anonymous 2020/3/12 16:39
*/
public class Demo3 {
	public static void main(String[] args) {
		/*
		明确调用对象
		当前方法是一个静态成员方法,需要通过类名
		调用
		明确调用方法
		showListInfo
		明确的数据
		ArrayList<String> list = new
		ArrayList<>();
		可省略,可推导
		*/
		testClass(ClassMethodReference::showListInfo);
		/*
		Lambda表达式
		*/
		testClass(list -> {
			for (Object o : list) {
				System.out.println(o);
			}
		});
	}
	/**
	* 利用了一个函数式接口作为方法的参数
	*
	* @param printList 函数式接口
	*/
	public static void testClass(PrintList printList) {
		ArrayList<String> list = new ArrayList<>();
		list.add("BMW");
		list.add("Audi");
		printList.print(list);
	}
}

通过super关键字执行方法引用

/**
* @author Anonymous 2020/3/12 16:52
*/
public interface SaySomeThing {
	void say();
}
/**
* @author Anonymous 2020/3/12 16:53
*/
public class Father {
	public void sayHello() {
		System.out.println("你好 Java");
	}
}
import java.util.Scanner;
/**
* @author Anonymous 2020/3/12 16:53
*/
public class Son extends Father {
	public static void main(String[] args) {
		//lambda
		testSay(() -> System.out.println("你好"));
		new Son().sonMethod();
	}
	/**
	* 这里的参数是一个函数式接口,这里需要提供给一个
	符合要求的方法
	* @param sst 函数式接口参数
	*/
	public static void testSay(SaySomeThing sst) {
		sst.say();
	}
	public void sonMethod() {
		/*
		父类中有一个无参数无返回值的sayHello
		满足当前SaySomeThing函数式接口,方法要求
		执行的对象
		super关键字,因为该方法在父类内
		执行的方法:
		sayHello
		无需参数
		*/
		testSay(super::sayHello);
	}
}

通过this关键字执行方法引用

/**
* @author Anonymous 2020/3/12 17:00
*/
public interface ORM {
	/**
	* int ==> String
	* @param i int类型
	* @return String类型
	*/
	String toStringType(int i);
}
/**
* @author Anonymous 2020/3/12 17:01
*/
public class ThisDemo {
	public void test() {
		String s = testThis(i -> i + ":");
		System.out.println(s);
		/*
		调用方法的对象
		this
		执行的方法:
		turn方法
		处理的数据
		10 (可省略,可联想)
		*/
		String s1 = testThis(this::turn);
	}
	public String turn(int i) {
		return i + ":字符串";
	}
	public static String testThis(ORM orm) {
		return orm.toStringType(10);
	}
	public static void main(String[] args) {
		new ThisDemo().test();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值