ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java8 Stream流操作最强详解版

2022-08-18 12:00:37  阅读:142  来源: 互联网

标签:Stream stream personList System Person 详解 new Java8 out


Java8 Stream流操作最强详解版

1. Stream简介

​ Java8 是Java 最受欢迎的一个版本,Stream是Java8提供的一个新的API,它位于java.util.stream包下。Stream API提供了一种新的方式来对Java集合进行操作,给我们操作集合(Collection)提供了极大的便利。其中的Stream流是JDK8新增的成员,是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以将元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等操作。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。Stream API 提供了一种高效且易于使用的处理数据的方式。

2. Stream概述

2.1 Stream特性

1.stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
2.stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
3.stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

2.2 Stream特点

1.代码简洁:函数编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环。
2.多核友好:Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法。
3.Stream不存储数据
4.Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
5.Stream是惰性求值的(延迟执行)

3. Stream创建

3.1 创建步骤

1.创建 Stream
一个数据源(如: 集合、数组), 获取一个流。
2.中间操作
一个中间操作链,对数据源的数据进行处理。
3.终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果 。

3.2 创建实例

1.通过 java.util.Collection.stream() 方法用集合创建流

List<String> list = new ArrayList<>();
//获取一个顺序流
Stream<String> stream = list.stream();
//获取一个并行流
Stream<String> parallelStream = list.parallelStream();

2.使用java.util.Arrays.stream(T[] array)方法用数组创建流

int[] array = {1, 3, 5, 7, 9};
IntStream stream = Arrays.stream(array);

3.使用Stream的静态方法:of()、iterate()、generate()

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
stream.forEach(System.out::println);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);

4. Stream流程

1)第一步:把集合转换为流stream
2)第二步:操作stream流
stream流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果
获取一个数据源(source)→ 数据转换→执行操作获取想要的结果。

5. Steam的使用

5.1 遍历/匹配

(foreach/find/match)操作

List<Integer> listNum = Arrays.asList(1, 2, 3, 8, 9, 5, 7);

// 遍历输出符合条件的元素
listNum.stream().filter(x -> x > 7).forEach(System.out::println);
// 符合条件的元素匹配第一个
Optional<Integer> findFirst = listNum.stream().filter(x -> x > 7).findFirst();
// 符合条件的元素匹配任意(适用于并行流)
Optional<Integer> findAny = listNum.parallelStream().filter(x -> x > 7).findAny();
// 是否包含符合特定条件的元素
boolean anyMatch = listNum.stream().anyMatch(x -> x > 7);
System.out.println("匹配第一个值:" + findFirst.get());
System.out.println("匹配任意一个值:" + findAny.get());
System.out.println("是否存在大于6的值:" + anyMatch);

//结果
8
9
匹配第一个值:8
匹配任意一个值:9
是否存在大于6的值:true

5.2 中间操作

流方法 含义
1 filter 用于通过设置的条件过滤出元素
2 distinct 返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流。
3 limit 会返回一个不超过给定长度的流。
4 skip 返回一个扔掉了前n个元素的流。
5 map 接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)。
6 flatMap 使用flatMap方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流。
7 sorted 返回排序后的流
5.2.1 筛选(filter)

按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

//案例一:筛选出Integer集合中大于6的元素,并打印出来。
public static void main(String[] args) {
    
    List<Integer> list = Arrays.asList(0, 6, 3, 5, 1, 2, 9, 7, 8);
    Stream<Integer> stream = list.stream();
    stream.filter(x -> x > 6).forEach(System.out::println);
}
//结果
9
7
8
  
//案例二:筛选出Person集合中年龄大于19员工姓名的元素,并打印出来。
public static void main(String[] args) {

    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, "shanghai"));
    personList.add(new Person(2, "lisi", 19, "beijing"));
    personList.add(new Person(3, "wanger", 20, "guangdong"));
    personList.add(new Person(4, "mazi", 21, "jiangxi"));
    personList.add(new Person(5, "laoer", 22, "zhejiang"));

    List<String> filterList = personList.stream().filter(x -> x.getAge() > 19).map(Person::getName)
        .collect(Collectors.toList());
    System.out.print("年龄大于19员工姓名:" + filterList);
}

//结果
年龄大于19员工姓名:[wanger, mazi, laoer]
5.2.2 去重(distinct)

通过流中元素的 hashCode()equals() 去除重复元素

//去除重复元素
public static void main(String[] args) {

    List<Integer> list = Arrays.asList(0, 6, 3, 5, 1, 2, 9, 7, 8);
    Stream<Integer> stream = list.stream();
    stream.filter(x -> x > 6).distinct().forEach(System.out::println);
}

//结果
9
7
8
5.2.3 跳过元素limit(n)

跳过n元素,配合limit(n)可实现分页

//跳过前两个元素
public static void main(String[] args) {

    List<Integer> list = Arrays.asList(0, 6, 3, 5, 1, 2, 9, 7, 8);
    Stream<Integer> stream = list.stream();
    stream.filter(x -> x > 6).skip(2).forEach(System.out::println);
}

//结果
8
5.2.4 获取元素skip(n)

获取n个元素

//获取第几个元素
public static void main(String[] args) {

    List<Integer> list = Arrays.asList(0, 6, 3, 5, 1, 2, 9, 7, 8);
    Stream<Integer> stream = list.stream();
    stream.filter(x -> x > 6).limit(2).forEach(System.out::println);
}

//结果
9
7
5.2.5 映射(map/flatMap)

可以将一个流的元素按照一定的映射规则映射到另一个流中

  • map: 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap: 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

其实map方法就相当于Collaction的add方法,如果add的是个集合得话就会变成二维数组,而flatMap 的话就相当于Collaction的addAll方法,参数如果是集合得话,只是将2个集合合并,而不是变成二维数组。

//案列一:整个数组的数组元素+10
public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    List<Integer> collect = list.stream().map(x -> x + 10).collect(Collectors.toList());
    System.out.println(collect);
}

//结果
[11, 12, 13, 14]

//案列二:将两个字符数组合并成一个新的字符数组。
public static void main(String[] args) {

    List<String> list = Arrays.asList("a,b,c,d", "e,f,g,h");
    List<String> listNew = list.stream().flatMap(s -> {
        // 将每个元素转换成一个stream
        String[] split = s.split(",");
        Stream<String> s2 = Arrays.stream(split);
        return s2;
    }).collect(Collectors.toList());
    System.out.println("转换前的数据:" + list);
    System.out.println("转换后后的数据:" + listNew);
}

//结果
转换前的数据:[a,b,c,d, e,f,g,h]
转换后后的数据:[a, b, c, d, e, f, g, h]
    
    
//案列三:将集合里的元素由小写变大写:
List<String> list = Arrays.asList("a", "b", "c", "d");
List<String> results = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(results);

//结果
{A, B, C, D}

//案列四:每个员工工资加3000
public static void main(String[] args) {

    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, 4000, "shanghai"));
    personList.add(new Person(2, "lisi", 19, 5000, "beijing"));
    personList.add(new Person(3, "wanger", 20, 6000, "guangdong"));
    personList.add(new Person(4, "mazi", 21, 7000, "jiangxi"));
    personList.add(new Person(5, "laoer", 22, 8000, "zhejiang"));

    // 不改变原来员工工资集合的方式
    List<Person> personListNew = personList.stream().map(person -> {
        Person personNew = new Person(0, person.getName(), 0, 0, null);
        personNew.setSalary(person.getSalary() + 3000);
        return personNew;
    }).collect(Collectors.toList());
    System.out.println("一次改动前:" +
                       personList.get(0).getName() + "-->" + 	personList.get(0).getSalary());
    System.out.println("一次改动后:" +
                       personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());

    // 改变原来员工工资集合的方式
    List<Person> personListNew2 = personList.stream().map(person -> {
        person.setSalary(person.getSalary() + 3000);
        return person;
    }).collect(Collectors.toList());
    System.out.println("二次改动前:" +
                       personList.get(0).getName() + "-->" + personListNew.get(0).getSalary());
    System.out.println("二次改动后:" +
                       personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary());
}

@Data
static class Person {
    private int id;
    private String name;
    private int age;
    private int salary;
    private String address;

    public Person(int id, String name, int age, int salary, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.address = address;
    }
}

//结果
一次改动前:zhangsan-->4000
一次改动后:zhangsan-->14000
二次改动前:zhangsan-->14000
二次改动后:zhangsan-->14000
5.2.6 排序(sorted)

sorted,中间操作。有两种排序:

  • sorted():自然排序,流中元素需实现 Comparable 接口
  • sorted(Comparator com):Comparator 排序器自定义排序
public static void main(String[] args) {

    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, 4000, "shanghai"));
    personList.add(new Person(2, "lisi", 19, 5000, "beijing"));
    personList.add(new Person(3, "wanger", 20, 6000, "guangdong"));
    personList.add(new Person(4, "mazi", 21, 7000, "jiangxi"));
    personList.add(new Person(5, "laoer", 22, 8000, "zhejiang"));

    //工资排序顺序
    List<Person> collect1 = personList.stream().sorted(Comparator.comparing(Person::getSalary)).collect(Collectors.toList());
    collect1.forEach(System.out::println);
}

//结果
test12.Person(id=1, name=zhangsan, age=18, salary=4000, address=shanghai)
test12.Person(id=2, name=lisi, age=19, salary=5000, address=beijing)
test12.Person(id=3, name=wanger, age=20, salary=6000, address=guangdong)
test12.Person(id=4, name=mazi, age=21, salary=7000, address=jiangxi)
test12.Person(id=5, name=laoer, age=22, salary=8000, address=zhejiang)

sorted排序参考模板

//返回 对象集合以类属性一升序排序
list.stream().sorted(Comparator.comparing(类::属性一));
//返回 对象集合以类属性一降序排序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,结果进行属性一降序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序
//返回 对象集合以类属性一升序 属性二升序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));

//返回 对象集合以类属性一降序 属性二升序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序

//返回 对象集合以类属性一降序 属性二降序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序
//返回 对象集合以类属性一升序 属性二降序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序

5.3 终止操作

流方法 含义
1 anyMatch 检查是否至少匹配一个元素,返回boolean。
2 allMatch 检查是否匹配所有元素,返回boolean。
3 noneMatch 检查是否没有匹配所有元素,返回boolean。
4 findAny 将返回当前流中的任意元素。
5 findFirst 返回第一个元素
6 forEach 遍历流
7 collect 收集器,将流转换为其他形式。
8 reduce 可以将流中元素反复结合起来,得到一个值。
9 max/min/count 返回流中元素最大/最小/总数。
5.3.2 收集(collect)
①归集(toList/toSet/toMap)
转化成新的List
List<> new = old.stream().collect(Collectors.toList());

转化成Map
Map<T,E> new= old.stream().collect(Collectors.toMap(T,E));

转换成set集合
Set<> new =old.stream().Collectors.toSet();

转换成特定的set集合
TreeSet<> new =old.stream().Collectors.toCollection(TreeSet::new);

转化成新的List

原始data:
List<User> userList = new ArrayList<>();
userList.add(new User(1, "张三", 18));
userList.add(new User(2, "李四", 19));
userList.add(new User(3, "王五", 20));

//user的id提取出来
List<User> users = userList;
List<Integer> idList = users.stream().map(User::getId).collect(Collectors.toList());
//{1, 2, 3}
System.out.println(idList);

转化成Map

//1.两个参数的用法
//将userList转化为key为id,value为User对象的map
Map<Integer, User> map1 = userList.stream().collect(Collectors.toMap(User::getId, p -> p));
Map<Integer, User> map2 = userList.stream().collect(Collectors.toMap(User::getId, p -> p));

//结果
{
    1: User(1, "张三", 18)
    2: User(2, "李四", 19)
    3: User(3, "王五", 20)
}

//2.三个参数的用法
Map<Integer, String> map3 = userList.stream().collect(Collectors.toMap(User::getAge, User::getName, (a, b) -> b));

//结果
{
    19: "李四"
    20: "王五"
}

//Collectors.groupingBy()
//当你想获取key是age的map,又不想覆盖掉重复项数据
Map<Integer, List<User>> map4 = userList.stream().collect(Collectors.groupingBy(User::getAge));
System.out.println(map4);

//结果
{
    18: [User(1, "张三", 18), User(3, "王五", 19)]
    19: [User(2, "李四", 20)]
}
②统计(count/averaging)

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

  • 计数:count
  • 平均值:averagingIntaveragingLongaveragingDouble
  • 最值:maxByminBy
  • 求和:summingIntsummingLongsummingDouble
  • 统计以上所有:summarizingIntsummarizingLongsummarizingDouble
public static void main(String[] args) {
    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, 4000, "shanghai"));
    personList.add(new Person(2, "lisi", 19, 5000, "beijing"));
    personList.add(new Person(3, "wanger", 20, 6000, "guangdong"));
    personList.add(new Person(4, "mazi", 21, 7000, "jiangxi"));
    personList.add(new Person(5, "laoer", 22, 8000, "zhejiang"));

    // 求总数
    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("员工工资总和:" + sum);
    System.out.println("员工工资所有统计:" + collect);

}

//结果
员工总数:5
员工平均工资:6000.0
员工工资总和:30000
员工工资所有统计:DoubleSummaryStatistics{count=5, sum=30000.000000, min=4000.000000, average=6000.000000, max=8000.000000}
③分组(partitioningBy/groupingBy)
  • 分区:将stream按条件分为两个Map,比如员工按薪资是否高于 8000 分为两部分。
  • 分组:将集合分为多个 Map,比如员工按性别分组。有单级分组和多级分组。
public static void main(String[] args) {
    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, 4000, "shanghai", "男"));
    personList.add(new Person(2, "lisi", 19, 5000, "beijing", "女"));
    personList.add(new Person(3, "wanger", 20, 6000, "guangdong", "男"));
    personList.add(new Person(4, "mazi", 21, 7000, "jiangxi", "男"));
    personList.add(new Person(5, "laoer", 22, 8000, "zhejiang", "女"));

    // 将员工按薪资是否高于8000分组
    Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
    // 将员工按性别分组
    Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
    // 将员工先按性别分组,再按地区分组
    Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getAddress)));
    System.out.println("员工按薪资是否大于5000分组情况:" + part);
    System.out.println("员工按性别分组情况:" + group);
    System.out.println("员工按性别、地区:" + group2);

}
④归约(reducing)

Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持。

public static void main(String[] args) {
    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, 4000, "shanghai", "男"));
    personList.add(new Person(2, "lisi", 19, 5000, "beijing", "女"));
    personList.add(new Person(3, "wanger", 20, 6000, "guangdong", "男"));
    personList.add(new Person(4, "mazi", 21, 7000, "jiangxi", "男"));
    personList.add(new Person(5, "laoer", 22, 8000, "zhejiang", "女"));

    Integer allAge = personList.stream().map(Person::getAge).collect(Collectors.reducing(Integer::sum)).get();
    System.out.println(allAge);
}  

//结果
100       
⑤接合(joining)

joining可以将 stream 中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。

public static void main(String[] args) {
    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person(1, "zhangsan", 18, 4000, "shanghai", "男"));
    personList.add(new Person(2, "lisi", 19, 5000, "beijing", "女"));
    personList.add(new Person(3, "wanger", 20, 6000, "guangdong", "男"));
    personList.add(new Person(4, "mazi", 21, 7000, "jiangxi", "男"));
    personList.add(new Person(5, "laoer", 22, 8000, "zhejiang", "女"));

    String names = personList.stream().map(t -> t.getName()).collect(Collectors.joining(","));
    System.out.println("所有员工的姓名:" + names);
    List<String> list = Arrays.asList("A", "B", "C");
    String string = list.stream().collect(Collectors.joining("&"));
    System.out.println("拼接后的字符串:" + string);

}

//结果
所有员工的姓名:zhangsan,lisi,wanger,mazi,laoer
拼接后的字符串:A&B&C
5.3.3 归约(reduce)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

//求和,求积
public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 7, 9);
    
    Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
    Optional<Integer> sum1 = list.stream().reduce(Integer::sum);
    Integer sum2 = list.stream().reduce(0, Integer::sum);
    
    Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
    // 最大值方式1
    Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
    // 最大值方式2
    Integer max1 = list.stream().reduce(1, Integer::max);
    System.out.println("求和:" + sum.get() + "," + sum1.get() + "," + sum2);
    System.out.println("求积:" + product.get());
    System.out.println("求和:" + max.get() + "," + max1);
}

//结果
求和:26,26,26
求积:1512
求和:9,9
5.3.4 聚合(max/min/count)

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

计数:count
平均值:averagingInt、averagingLong、averagingDouble
最值:maxBy、minBy
求和:summingInt、summingLong、summingDouble
统计以上所有:summarizingInt、summarizingLong、summarizingDouble

//获取最长元素
public static void main(String[] args) {
    List<String> list = Arrays.asList("asdas", "asdasdasd", "sdasd", "fdfdf", "qqe");
    Optional<String> max = list.stream().max(Comparator.comparing(String::length));
    System.out.println("最长的字符串:" + max.get());
}

//结果
最长的字符串:asdasdasd
5.3.5 匹配(find/match)
//匹配示例
public static void main(String[] args) {
    List<String> strings = Arrays.asList("123", "456", "abc", "sdf", "qwe", "qw2", "qwe");
    //anyMatch  判断集合中是否至少存在一个元素满足条件
    boolean a = strings.stream().anyMatch("123"::equals);
    System.out.println(a);
    //allMatch 判断集合中是否所有元素都满足条件
    boolean b = strings.stream().allMatch("123"::equals);
    System.out.println(b);
    //noneMatch 判断集合中是否所有元素都不满足条件
    boolean c = strings.stream().noneMatch("123"::equals);
    System.out.println(c);
    //findAny 返回当前流中任意元素
    Optional<String> any = strings.stream().findAny();
    any.ifPresent(System.out::println);
    //findFirst 返回当前流中第一个元素
    Optional<String> first = strings.stream().findFirst();
    first.ifPresent(System.out::println);
}

//结果
true
false
false
123
123

6. Steam的总结

Stream极大的简化了开发的代码量,Stream API提供了多个方法对集合进行映射、过滤、排序等操作,其操作不会对原始的集合产生影响,这边列举了部分例子供参考,仅作为学习笔记使用,欢迎批评指正,要是感兴趣可以关注微信订阅号 程序own

标签:Stream,stream,personList,System,Person,详解,new,Java8,out
来源: https://www.cnblogs.com/ProgramOwn/p/16598208.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有