当前位置: 首页 > news >正文

鸣蝉智能建站重庆网站设计

鸣蝉智能建站,重庆网站设计,深圳网站设计公司yx成都柚米科技15,wordpress企业主题免费Java8新特性#xff08;二#xff09; Stream与Optional详解 一. Stream流 1. Stream概述 1.1 基本概念 Stream#xff08;java.util.stream#xff09; 是Java 8中新增的一种抽象流式接口#xff0c;主要用于配合Lambda表达式提高批量数据的计算和处理效率。Stream不是…Java8新特性二 Stream与Optional详解 一. Stream流 1. Stream概述 1.1 基本概念 Streamjava.util.stream 是Java 8中新增的一种抽象流式接口主要用于配合Lambda表达式提高批量数据的计算和处理效率。Stream不是一种数据结构它是来自数据源的一种元素序列组织视图并支持一系列聚合操作比如过滤、排序、映射、遍历等其中数据源可以是一个数组、集合或I/O channel等。 Stream的主要目的在于计算它以一种声明性方式处理数据集合与数据是函数式编程模式的重要体现。关于Stream流可以把它理解为一种管道式的操作集它允许将一系列计算过程进行链式封装并像流水线一样对数据源进行处理最后生成并返回结果集合。 1.2 操作流程 1流的创建 一个数据源如集合、数组等用于获取一个流 2中间操作 一个中间操作链包含多个中间操作每个中间操作都会返回一个新的流用于对数据源的数据进行处理 3终止操作 一个终止操作用于执行中间操作链并产生最终结果注意终止操作后该Stream就不能再使用了 1.3 基本特性 惰性求值 流上的中间操作不会立即执行仅创建视图只有在遇到终止操作时才会触发计算非数据结构 不会保存数据也不会存储元素只保存操作不改变源数据 不会改变源数据计算结果会保存到新的流中但对于对象引用来说可以修改其属性值 2. 流的创建 2.1 从数组创建 Stream.of 调用Stream类的静态方法 of()通过显示值创建一个流Arrays.stream 调用Arrays 的静态方法 stream()来从数组中创建一个流 Integer[] arr {1,2,3,4,5}; StreamInteger stream_arr Arrays.stream(arr); // StreamInteger stream_of Stream.of(1, 2, 3, 4, 5); StreamInteger stream_of Stream.of(arr);2.2 从单列集合 单列集合如List、SetJava8 中的 Collection 接口被扩展提供了获取集合流的方法 Collection.stream() ListString names Arrays.asList(Alice, Bob, Charlie, David); StreamString stream names.stream();2.3 从双列集合 双列集合如Map一般转换成单列集合后再创建流 MapString,Integer ids new HashMap(); ids.put(小新,19); ids.put(黑子,17); ids.put(哆啦,16); StreamMap.EntryString, Integer stream ids.entrySet().stream();3. 数据准备 Data AllArgsConstructor NoArgsConstructor EqualsAndHashCode//用于后期的去重使用 public class Book {//idprivate Long id;//书名private String name;//分类private String category;//评分private Integer score;//简介private String intro; }Data NoArgsConstructor AllArgsConstructor EqualsAndHashCode//用于后期的去重使用 public class Author {//idprivate Long id;//姓名private String name;//年龄private Integer age;//国家private String country;//作品private ListBook books; }private static ListAuthor getAuthors() {//数据初始化Author author1 new Author(1L, 鲁迅, 55, 中国, null);Author author2 new Author(2L, 维克多.雨果, 83, 法国, null);Author author3 new Author(3L, 安东.巴甫洛维奇.契诃夫, 44, 俄国, null);Author author4 new Author(3L, 安东.巴甫洛维奇.契诃夫, 44, 俄国, null);//书籍列表ListBook books1 new ArrayList();ListBook books2 new ArrayList();ListBook books3 new ArrayList();books1.add(new Book(1L, 朝花夕拾, 散文,回忆, 82, 这部作品收录了鲁迅于1926年创作的10篇回忆性散文));books1.add(new Book(2L, 孔乙己, 短篇小说,讽刺, 99, 深刻揭示了当时社会的黑暗面));books2.add(new Book(3L, 巴黎圣母院, 长篇小说,浪漫主义, 75, 通过离奇和对比手法描述了15世纪法国的故事));books2.add(new Book(3L, 巴黎圣母院, 长篇小说,浪漫主义, 75, 通过离奇和对比手法描述了15世纪法国的故事));books2.add(new Book(4L, 悲惨世界, 现实,长篇小说, 86, 这部小说跨越了拿破仑战争及其后的十几年历史));books3.add(new Book(5L, 变色龙, 短篇小说,讽刺, 86, 巧妙地讽刺了沙皇专制制度下封建卫道士的卑躬屈膝和虚伪));books3.add(new Book(6L, 装在套子里的人, 短篇小说, 100, 深刻地揭示了专制制度对个体思想的毒化以及别里科夫这样的角色如何成为阻碍社会进步的代表));books3.add(new Book(6L, 装在套子里的人, 短篇小说, 100, 深刻地揭示了专制制度对个体思想的毒化以及别里科夫这样的角色如何成为阻碍社会进步的代表));author1.setBooks(books1);author2.setBooks(books2);author3.setBooks(books3);author4.setBooks(books3);ListAuthor authorList new ArrayList(Arrays.asList(author1, author2, author3, author4));return authorList;}4. 中间操作 4.1 筛选与切片 方法描述filter(Predicate predicate)可以对流中的元素进行条件过滤符合过滤条件的才能继续留在流中Predicate为Truedistinct()可以去除流中的重复元素通过元素的 hashCode 和 equals 去重limit(long maxSize)截断流使流中元素不超过给定数量maxSize超出的部分将被抛弃若数量不足则全保留skip(long n)跳过流中的前n个元素返回剩余元素的流若流中元素不足n个则返回空流 1filter 打印所有姓名长度大于2的作家的姓名。 public static void main(String[] args) {ListAuthor authors getAuthors();//匿名内部类authors.stream().filter(new PredicateAuthor() {Overridepublic boolean test(Author author) {return author.getName().length() 2;}}).forEach(author - System.out.println(author.getName()));//Lambdaauthors.stream().filter(author - author.getName().length() 2).forEach(author - System.out.println(author.getName()));}2distinct distinct方法通过元素的 hashCode 和 equals 方法判断去重只有两元素的equals返回True且同时hashCode也相等才认为是相同元素。注意使用时要重写 hashCode 和 equals逻辑上来说 equals 方法判断两个对象是相等的那这两个对象的 hashCode 值也一定要相等两个对象有相同的 hashCode 值他们也不一定是相等的哈希碰撞 打印所有作家的姓名并且要求其中不能有重复元素。 public static void main(String[] args) {ListAuthor authors getAuthors();authors.stream().distinct().forEach(author - System.out.println(author.getName()));}3limit 打印流中前两个作家的姓名。 public static void main(String[] args) {ListAuthor authors getAuthors();authors.stream().limit(2).forEach(author - System.out.println(author.getName()));}4skip 打印流中除第一个作家外的剩余作家的姓名。 public static void main(String[] args) {ListAuthor authors getAuthors();authors.stream().skip(1).forEach(author - System.out.println(author.getName()));}4.2 映射 方法描述map(Function mapper)接收一个计算函数该函数会被应用到每个元素上并将其映射/转换成一个新的元素一对一多流独立flatMap(Function mapper)接收一个计算函数将流中的每个元素都转换成另一个流并把所有流连接成一个流一对多多流混合 1map 提取作家的姓名长度并筛选长度大于2的值。 public static void main(String[] args) {ListAuthor authors getAuthors();//匿名内部类authors.stream().map(new FunctionAuthor, Integer() {Overridepublic Integer apply(Author author) {return author.getName().length();}}).filter(new PredicateInteger() {Overridepublic boolean test(Integer len) {return len 2;}}).forEach(val - System.out.println(val));//Lambdaauthors.stream().map(author - author.getName().length()).filter(len - len 2).forEach(val - System.out.println(val));}提取作家的年龄并转换为10年后的值。 public static void main(String[] args) {ListAuthor authors getAuthors();// 匿名内部类authors.stream().map(new FunctionAuthor, Integer() {Overridepublic Integer apply(Author author) {return author.getAge();}}).map(new FunctionInteger, Integer() {Overridepublic Integer apply(Integer age) {return age 10;}}).forEach(age- System.out.println(age));//Lambdaauthors.stream().map(author - author.getAge()).map(age - age 10).forEach(age- System.out.println(age));}2flatMap 打印所有书籍的名字要求对重复的元素进行去重。 public static void main(String[] args) {ListAuthor authors getAuthors();// 匿名内部类authors.stream().flatMap(new FunctionAuthor, StreamBook() { // Author - StreamBookOverridepublic StreamBook apply(Author author) {return author.getBooks().stream();}}).distinct().forEach(book - System.out.println(book.getName()));//Lambdaauthors.stream().flatMap(author - author.getBooks().stream()).distinct().forEach(book - System.out.println(book.getName()));}打印现有书籍的所有独立分类并对分类进行去重分类中不能出现 ‘,’ public static void main(String[] args) {ListAuthor authors getAuthors();// 匿名内部类authors.stream().flatMap(new FunctionAuthor, StreamBook() { // Author - StreamBookOverridepublic StreamBook apply(Author author) {return author.getBooks().stream();}}).distinct().flatMap(new FunctionBook, StreamString() { // Book - StreamStringOverridepublic StreamString apply(Book book) {return Arrays.stream(book.getCategory().split(,));}}).distinct().forEach(category- System.out.println(category));//Lambdaauthors.stream().flatMap(author - author.getBooks().stream()).distinct().flatMap(book - Arrays.stream(book.getCategory().split(,))).distinct().forEach(category- System.out.println(category));}4.3 排序 方法描述sorted()对流中元素按默认规则排序类内必须实现Comparable接口sorted(Comparator com)对流中元素按比较器规则排序 对流中的元素按照年龄进行降序排序并且要求不能有重复的元素。 1实现Comparable接口 //实现Comparable接口 public class Author implements ComparableAuthor {//idprivate Long id;//姓名private String name;//年龄private Integer age;//国家private String country;//作品private ListBook books;//负整数、零或正整数因为此对象小于、等于或大于指定对象。Overridepublic int compareTo(Author another) {return another.getAge() - this.getAge();} }//降序排序 public static void main(String[] args) {ListAuthor authors getAuthors();authors.stream().distinct().sorted().forEach(author - System.out.println(author.getAge())); }2自定义比较器Comparator public static void main(String[] args) {ListAuthor authors getAuthors();// 匿名内部类authors.stream().distinct().sorted(new ComparatorAuthor() {Overridepublic int compare(Author o1, Author o2) {return o2.getAge() - o1.getAge();}}).forEach(author - System.out.println(author.getAge()));//Lambdaauthors.stream().distinct().sorted((o1, o2) - o2.getAge() - o1.getAge()).forEach(author - System.out.println(author.getAge()));}5. 终止操作 5.1 遍历与统计 方法描述void forEach(Consumer action)迭代遍历流中的每个元素并执行 actionlong count()返回当前流中的元素总数Optional max(Comparator c)返回当前流中的最大值OptionalOptional min(Comparator c)返回当前流中的最小值Optional 1count 打印作家所出的所有书籍的数目注意删除重复元素。 public static void main(String[] args) {ListAuthor authors getAuthors();long count authors.stream().flatMap(author - author.getBooks().stream()).distinct().count();System.out.println(count);}2maxmin 分别获取这些作家的所出书籍的最高分和最低分并打印。 public static void main(String[] args) {ListAuthor authors getAuthors();OptionalInteger max authors.stream().flatMap(author - author.getBooks().stream()).map(book - book.getScore()).max((score1, score2) - score1 - score2);OptionalInteger min authors.stream().flatMap(author - author.getBooks().stream()).map(book - book.getScore()).min((score1, score2) - score1 - score2);System.out.println(max.get());System.out.println(min.get());}5.2 匹配与查找 方法描述boolean anyMatch(Predicate p)检查流中是否至少包含一个满足匹配条件的元素boolean allMatch(Predicate p)检查流中所有元素是否都满足匹配条件boolean noneMatch(Predicate p)检查流中所有元素是否都不满足匹配条件Optional findFirst()返回当前流中的第一个元素可能为空Optional findAny()返回当前流中的任意一个元素无法保证获取的是流中首位元素可能为空 1anyMatch 判断是否有年龄在29以上的作家。 public static void main(String[] args) {ListAuthor authors getAuthors();// 匿名内部类boolean flag authors.stream().anyMatch(new PredicateAuthor() {Overridepublic boolean test(Author author) {return author.getAge() 80;}});System.out.println(flag);//Lambdaboolean flag_lambda authors.stream().anyMatch(author - author.getAge() 80);System.out.println(flag_lambda);}2allMatch 判断是否所有的作家都是成年人。 public static void main(String[] args) {ListAuthor authors getAuthors();boolean flag authors.stream().allMatch(author - author.getAge() 18);System.out.println(flag);}3noneMatch 判断作家的书籍列表是否都没有超过3本包含重复。 public static void main(String[] args) {ListAuthor authors getAuthors();boolean flag authors.stream().noneMatch(author - author.getBooks().size() 3);System.out.println(flag);}4findFirst 获取一个年龄最大的作家并输出他的姓名。 public static void main(String[] args) {ListAuthor authors getAuthors();OptionalAuthor first authors.stream().sorted((o1, o2) - o2.getAge() - o1.getAge()).findFirst();first.ifPresent(new ConsumerAuthor() {Overridepublic void accept(Author author) {System.out.println(author.getName());}});}5findAny 获取任意一个年龄大于18的作家如果存在就输出他的名字。 public static void main(String[] args) {ListAuthor authors getAuthors();OptionalAuthor optionalAuthor authors.stream().filter(author - author.getAge()18).findAny();optionalAuthor.ifPresent(new ConsumerAuthor() {Overridepublic void accept(Author author) {System.out.println(author.getName());}});}5.3 收集 方法描述collect(Collector c)将流中的元素转换为另一种数据存储形式。Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、Map)除此之外Collectors 实用类提供了很多现成的静态方法来创建常见收集器实例。 参考文章 Java Stream collect 本节不考虑自定义Collector接口实现类的方式只介绍结合Collectors工具类的主要使用方法主要包括集合转换、分组分区两大功能模块其中collect、Collector、Collectors的区别和关联如下。 5.3.1 集合转换 方法描述Collectors.toList将流中的元素收集到一个List中Collectors.toSet将流中的元素收集到一个Set中自动去重Collectors.toCollection将流中的元素收集到一个Collection中Collectors.toMap将流中的元素映射收集到一个Map中若包含相同key则需提供第三参数 public static void main(String[] args) {ListAuthor authors getAuthors();// 1.获取一个存放所有作者名字的List集合ListString nameList authors.stream().map(author - author.getName()).collect(Collectors.toList());System.out.println(nameList);// 2.获取一个所有书名的Set集合(自动去重)SetBook books authors.stream().flatMap(author - author.getBooks().stream()).collect(Collectors.toSet());System.out.println(books);// 3.获取一个Map集合map的key为作者名value为ListBook(若包含相同key则需提供第三参数否则报错)MapString, ListBook map authors.stream().distinct().collect(Collectors.toMap(author - author.getName(), author -author.getBooks()));System.out.println(map);// 4.获取一个存放所有作者名字的ArrayList集合指定具体容器类型ArrayListString nameArrList authors.stream().map(author - author.getName()).collect(Collectors.toCollection(ArrayList::new));System.out.println(nameArrList);}5.3.2 分组分区 方法含义说明Collectors.groupingBy根据给定的分组函数的值进行分组输出一个Map对象Collectors.partitioningBy根据给定的分区函数的值进行分区输出一个Map对象且key始终为布尔值类型 Collectors.partitioningBy()分区收集器的使用方式与Collectors.groupingBy()分组收集器的使用方式基本相同其区别在于划分维度其中分组收集器可以有多个组的划分而分区收集器只会有两个区( true 和 false) 的划分单纯从使用维度来看若分组收集器的分组函数返回值为布尔值则其效果等同于一个分区收集器。因此本节只有着重介绍分组收集器groupingBy的使用。 1方法概述 groupingBy()操作需要指定三个关键输入即分组函数、分组容器和值收集器 分组函数一个处理函数用于基于指定的元素进行处理返回一个用于分组的值即分组结果Map的Key值对于经过此函数处理后返回值相同的元素将被分配到同一个组里容器函数一个生成容器的函数当调用该函数时生成所需类型的新空Map值收集器对于分组后的数据元素的进一步处理转换逻辑即value的处理和存储逻辑此处还是一个常规的Collector收集器和collect()方法中传入的收集器完全等同多用于实现分组数据统计、多级分组等操作 为了方便使用在Collectors工具类中提供了三个groupingBy重载实现其源码如下 //单参数需要传入classifier分组函数默认使用了HashMap作为容器函数使用了toList()作为值收集器 public static T, K CollectorT, ?, MapK, ListT groupingBy(Function? super T, ? extends K classifier) {return groupingBy(classifier, toList()); } //双参数需要传入classifier分组函数和downstream值收集器 public static T, K, A, D CollectorT, ?, MapK, D groupingBy(Function? super T, ? extends K classifier,Collector? super T, A, D downstream) {return groupingBy(classifier, HashMap::new, downstream); } //三参数可用于指定自定义Map容器比如LinkedHashMap::new public static T, K, D, A, M extends MapK, D CollectorT, ?, M groupingBy(Function? super T, ? extends K classifier,SupplierM mapFactory,Collector? super T, A, D downstream) {//... }2实例分析 public class Test {public static void main(String[] args) {ListStudent students getStudents();// 1. 按照单维度分组按照是否成年分组匿名函数MapString, ListStudent collect1 students.stream().collect(Collectors.groupingBy(new FunctionStudent, String() {Overridepublic String apply(Student student) {if (student.getAge() 18) {return 未成年;} else {return 已成年;}}}));System.out.println(collect1);// 2. 分组与组内数据的处理统计男女性别各有多少人lambdaMapString, Long collect2 students.stream().collect(Collectors.groupingBy(student - {if (student.getGender() 1) {return 男;} else {return 女;}}, Collectors.counting()));System.out.println(collect2);// 3. 多级分组先按国家分组然后按照成绩是否及格分组MapString, MapString, ListStudent collect3 students.stream().collect(Collectors.groupingBy(student - student.getCountry(),Collectors.groupingBy(student - {if (student.getScore() 60) {return 及格;} else {return 不及格;}})));System.out.println(collect3);}private static ListStudent getStudents() {//数据初始化Student student1 new Student(1,张三,1,祖安,17,88);Student student2 new Student(2,王雪,0,祖安,23,92);Student student3 new Student(3,李四,1,德玛西亚,31,74);Student student4 new Student(4,赵一,1,祖安,25,58);Student student5 new Student(5,安琪拉,0,德玛西亚,19,66);Student student6 new Student(6,大桥,0,德玛西亚,13,86);ListStudent students new ArrayList();students.add(student1);students.add(student2);students.add(student3);students.add(student4);students.add(student5);students.add(student6);return students;} }5.4 归并 方法描述reduce(T identity, BinaryOperator accumulator)可以将流中元素反复结合起来得到一个值返回T。其中identity是初始值accumulator是归并计算方法。reduce(BinaryOperator accumulator)可以将流中元素反复结合起来得到一个值返回 OptionalT。其中accumulator是归并计算方法初始值默认为流中第一个元素。 1双参方法源码 T result identity; for (T element : this stream)result accumulator.apply(result, element) return result;2单参方法源码 boolean foundAny false; T result null; for (T element : this stream) {if (!foundAny) {foundAny true;result element;}elseresult accumulator.apply(result, element); } return foundAny ? Optional.of(result) : Optional.empty();3实例分析 public static void main(String[] args) {ListAuthor authors getAuthors();// 使用reduce求所有作者年龄的和(匿名函数)Integer sum authors.stream().distinct().map(author - author.getAge()).reduce(0, new BinaryOperatorInteger() {Overridepublic Integer apply(Integer result, Integer element) {return result element;}});System.out.println(sum);// 使用reduce求所有作者中年龄的最大值Integer max authors.stream().map(author - author.getAge()).reduce(Integer.MIN_VALUE, (result, element) - result element ? element : result);System.out.println(max);// 使用reduce求所有作者中年龄的最小值单参方法OptionalInteger minOptional authors.stream().map(author - author.getAge()).reduce((result, element) - result element ? element : result);minOptional.ifPresent(age- System.out.println(age));}6. 并行流 当流中有大量元素时我们可以使用并行流去提高操作的效率其本质就是把任务拆分并分配给多个线程去完成核心是通过Fork/Join框架实现。获取并行流的方式有两种 parallel() 把串行流转换成并行流parallelStream() 从数据源中直接获取并行流对象 public static void main(String[] args) {StreamInteger stream Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);/*** peek(Consumer c)* - 中间操作: 对流中的每个元素执行操作,而不影响流的整体后续处理流程* - 特点: 不改变流的原始内容也不决定流的最终输出结果* - 用途: action动作会在流的每个元素上执行一次但具体执行多少次取决于下游的终端操作* - 注意* - 对于并行流peek()操作的执行顺序没有保证而且可能会多次执行* - peek()通常用于读取或打印流元素而不是修改它们。虽然理论上可以尝试在peek()中修改元素但由于流的惰性求值和可能的不可变性这样的修改可能不会反映到源集合或后续流操作中。*///1. parallel转化Integer sum stream.parallel().peek(new ConsumerInteger() {Overridepublic void accept(Integer num) {System.out.println(numThread.currentThread().getName());}}).filter(num - num 5).reduce((result, ele) - result ele).get();System.out.println(sum);//2. parallelStream直接获取ListAuthor authors getAuthors();authors.parallelStream().map(author - author.getAge()).map(age - age 10).filter(age-age18).map(age-age2).forEach(System.out::println);}二. Optional 1.Optional概述 我们在编写代码的时候出现最多的就是空指针异常NPE所以在很多情况下需要人为做各种非空的判断但这种方式会让代码变得臃肿不堪、难以理解为了解决这个问题JDK8中引入了Optional容器类用于封装结果或数据并提供一系列空值检测和处理方法这使得我们可以通过更优雅的方式来避免空指针异常情况。 注意 Mybatis 3.5版本已支持Optional当dao方法的返回值类型定义成Optional类型时MyBastis会自动将数据封装成Optional对象返回。 2.Optional使用 2.1 创建对象 方法描述Optional.empty返回一个空的 Optional 实例其封装数据为nullOptional.of将指定值用 Optional 封装之后返回如果该值为 null则会抛出一个 NullPointerException 异常Optional.ofNullable将指定值用 Optional 封装之后返回如果该值为 null则返回一个空的 Optional 对象无异常 Author author getAuthor(); // 1.一般使用Optional的静态方法ofNullable来把数据封装成一个Optional对象 OptionalAuthor authorOptional1 Optional.ofNullable(author); // 2.当确定一个对象不是空的则可以使用Optional的静态方法of来把数据封装成Optional对象 OptionalAuthor authorOptional2 Optional.of(author); // 3.通过静态工厂方法 Optional.empty()创建一个空的 Optional 对象 OptionalAuthor authorOptional3 Optional.empty();2.2 常用方法 方法描述get如果该值存在将该值返回否则抛出一个 NoSuchElementException 异常不安全ifPresent(Comsumer c)如果值存在就执行使用该值的消费方法Comsumer否则什么也不做isPresent()如果值存在就返回 true否则返回 falseorElse(T other)如果有值则将其返回否则返回一个默认值otherorElseGet(Supplier other)如果有值则将其返回否则返回一个由指定的 Supplier 接口生成的值orElseThrow(Supplier exceptionSupplier)如果有值则将其返回否则抛出一个由指定的 Supplier 接口生成的异常filter如果值存在并且满足提供的谓词就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象map如果值存在就对该值执行提供的mapping 函数调用 OptionalAuthor authorOptional Optional.ofNullable(getAuthor()); // 安全消费值 authorOptional.ifPresent(author -System.out.println(author.getName())); // 安全获取值 Author author1 authorOptional.orElseGet(() - new Author());
http://www.w-s-a.com/news/918787/

相关文章:

  • 比较好的室内设计网站潍坊网络科技
  • 南宁网站建设公设计联盟网站
  • 多个图表统计的网站怎么做百度推广费2800元每年都有吗
  • 连江县住房和城乡建设局网站企业类网站模版
  • 临沂seo整站优化厂家网站建设 大公司排名
  • 网站开发有哪些方式百度导航怎么下载
  • 网站认证免费视频直播网站建设方案
  • 瀑布流分享网站源代码下载网站构建的一般流程是什么
  • wordpress 4.9 多站wordpress邮箱解析
  • 微信网站开发企业汽车网站设计模板
  • 如何提升网站转化率遵义市公共资源交易平台
  • 网站目录管理模板企业解决方案部
  • 建设网站上申请劳务资质吗珠海哪个公司建设网站好
  • c2c商城网站建设在微信怎么开发公众号
  • 美的公司网站建设的目的做个网站要钱吗
  • 和县建设局网站孟州网站建设
  • 网站与规划设计思路竞价培训课程
  • 网站建设设计视频专业设计企业网站
  • 湖南省建设工程网站cerntos wordpress
  • 主机屋的免费空间怎么上传网站广告公司的经营范围有哪些
  • 门户网站建设公司案例门户建设是什么意思
  • 深圳seo专家东莞网站关键词优化排名
  • 套用别人产品图片做网站如何在阿里云自主建网站
  • 网站开发需要用哪些东西wordpress页面参数
  • 大连模板网站制作哪家好wordpress 安装不上
  • 宝塔搭建网站首页图片点击率如何提高
  • 长沙找人做网站wordpress如何安装模板
  • 比较好的国外网站建设公司wordpress短代码可视化
  • 做新的网站网站个性化
  • 吉安做网站的英文网站 字体大小