(尊重劳动成果,转载请注明出处:https://blog.csdn.net/qq_25827845/article/details/87903464冷血之心的博客)

目录

背景:

正文:

Lambda表达式

定义

语法

示例

总结:

默认方法

总结:

Stream API

什么是 Stream?

生成流

总结:

总结:


背景:

JDK8发布于2014年3月18号,而我入坑Java是在2015年1月的本科毕业设计期间。大学本科最后一学期以及整个研究生期间,都在不断的入门学习Java相关基础知识和相关热门框架的使用,一直没有深入了解JDK8中出现的新特性(一直感觉好像用不到的样子>_<),只是为了应对校招面试简单的进行了一个了解。写这篇博客的原因是:同事在实际项目中使用JDK8新特性写了一段代码,使我感觉到使用JDK8新特性确实可以写出简洁而又高效的代码,这与我的追求(致力于写出优雅而又高效的代码)保持一致。所以,好记性不如烂笔头,我们一起来总结一下吧~

正文:

Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。其中,比较重要的新特性如下:

  • Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中
  • 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与Lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码
  • 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法
  • 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps
  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中
  • Date Time API − 加强对日期与时间的处理
  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常
  • Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用
  • JVM方面 − 由元空间代替了永久代
  • HashMap − 底层实现增加了红黑树
  • 注解 − 引入了重复注解,使用@Repeatable,注解的使用场景拓宽
  • 更好的类型判断 − Value.defaultValue()

这篇博客,我们主要来总结学习Lambda表达式、默认方法以及Stream API的使用。

Lambda表达式

定义

Lambda表达式(也称为闭包),允许我们将函数当成参数传递给某个方法,或者把代码本身当做数据处理;

语法

Lambda 表达式的语法格式如下:

(parameters) -> expression
或
(parameters) ->{ statements; }

lambda表达式的重要特征如下:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

示例

Lambda表达式的简单使用如下:

// 1. 不需要参数,返回值为 5
() -> 5  // 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x  // 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y  // 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y  // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

Demo

package com.pak2;public class Test {public static void main(String args[]){Test tester = new Test();// 类型声明MathOperation addition = (int a, int b) -> a + b;// 不用类型声明MathOperation subtraction = (a, b) -> a - b;// 大括号中的返回语句MathOperation multiplication = (int a, int b) -> { return a * b; };// 没有大括号及返回语句MathOperation division = (int a, int b) -> a / b;System.out.println("10 + 5 = " + tester.operate(10, 5, addition));System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));System.out.println("10 / 5 = " + tester.operate(10, 5, division));// 不用括号GreetingService greetService1 = message -> System.out.println("Hello " + message);// 用括号GreetingService greetService2 = (message) -> System.out.println("Hello " + message);greetService1.sayMessage("Runoob");greetService2.sayMessage("Google");}interface MathOperation {int operation(int a, int b);}interface GreetingService {void sayMessage(String message);}private int operate(int a, int b, MathOperation mathOperation){return mathOperation.operation(a, b);}
}

上述代码的输出如下所示:

总结:

  • Lambda 表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
  • Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。

注意:在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。如下图所示,编译会提示出错。

String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //编译会出错 

接下来,我们接着看看默认方法的特性。

默认方法

在面试的时候,你可能被问过这么一个问题,那就是:“Java中抽象类和接口的区别有哪些?” 也许你曾经这么回答过。 “抽象类中可以有已经实现的普通方法, 但是接口中都是抽象方法”。恭喜你,你的这一条区别在JDK8之前是没有问题的。但是,在JDK8发布之后就有待商榷了。因为JDK8中允许接口有默认方法的存在。

简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。

我们来看一个例子:

package com.pak2;public interface MyInterface {// 定义一个已经实现的方法,使用default表明default void say(String message){System.out.println("Hello "+message);}// 普通的抽象方法void test();
}

那么JDK8中为什么要有这个特性?

首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题

当一个类实现多个接口时,可以继承到每一个接口中定义的默认方法;

package com.pak2;public interface MyInterface {// 定义一个已经实现的方法,使用default表明default void say(String message){System.out.println("Hello "+message);}// 普通的抽象方法void test();
}class MyClass implements MyInterface{@Overridepublic void test() {System.out.println("test...");}
}class Main{public static void main(String[] args) {MyClass client = new MyClass();client.test();client.say("World...");}
}

我们再来看一下,当多个接口中的默认方法相同时,接口的实现类该如何处理?

public interface MyInterface {// 定义一个已经实现的方法,使用default表明default void say(String message){System.out.println("Hello "+message);}// 普通的抽象方法void test();
}
interface MyInterface2{// 定义一个已经实现的方法,使用default表明default void say(String message){System.out.println("[2]-Hello "+message);}
}
// 此处会编译错误
class MyClass implements MyInterface, MyInterface2{@Overridepublic void test() {System.out.println("test...");}
}

会出现编译错误,如图所示:

意思就是说,有两个相同的方法,编译器不知道该如何选择了,所以我们需要处理:

  • 重写多个接口中的相同的默认方法
  • 在实现类中指定要使用哪个接口中的默认方法

(1)重写多个接口中的相同的默认方法

class MyClass implements MyInterface, MyInterface2{@Overridepublic void say(String message) {System.out.println("[Client]-Hello "+message);}@Overridepublic void test() {System.out.println("test...");}
}

(2)在实现类中指定要使用哪个接口中的默认方法

class MyClass implements MyInterface, MyInterface2{// 手动指定哪个默认方法生效public void say(String message) {MyInterface.super.say(message);}@Overridepublic void test() {System.out.println("test...");}
}

总结:

由于JVM上的默认方法的实现在字节码层面提供了支持,因此效率非常高。默认方法允许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()parallelStream()forEach()removeIf()等等。尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引起歧义和编译错误。

也就是说,默认接口的出现是为了解决接口的修改与现有的实现不兼容的问题。 我们来看下JDK8中新增的Stream流,因为接口默认方法的实现,才可以在Collection接口中新增了方法stream()等。

Stream API

其实,这篇博客的灵感就来自于同事在处理List集合的时候写了几行简洁而又优雅的代码,勾起了我想要学习的欲望。

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

将以上的图片转换为代码那就是:

List<Integer> transactionsIds =
widgets.stream().filter(b -> b.getColor() == RED).sorted((x,y) -> x.getWeight() - y.getWeight()).mapToInt(Widget::getWeight).sum();

什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

生成流

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream() − 为集合创建串行流。

  • parallelStream() − 为集合创建并行流。

Stream可以帮助我们在处理集合(Collection)的时候写出优雅而又简洁的代码(当然需要结合前面提到的Lambda表达式),这是一个孰能生巧的过程,此处我们直接引用别人总结好的案例来看一下:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;public class Java8Tester {public static void main(String args[]){System.out.println("使用 Java 7: ");// 计算空字符串List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");System.out.println("列表: " +strings);long count = getCountEmptyStringUsingJava7(strings);System.out.println("空字符数量为: " + count);count = getCountLength3UsingJava7(strings);System.out.println("字符串长度为 3 的数量为: " + count);// 删除空字符串List<String> filtered = deleteEmptyStringsUsingJava7(strings);System.out.println("筛选后的列表: " + filtered);// 删除空字符串,并使用逗号把它们合并起来String mergedString = getMergedStringUsingJava7(strings,", ");System.out.println("合并字符串: " + mergedString);List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);// 获取列表元素平方数List<Integer> squaresList = getSquares(numbers);System.out.println("平方数列表: " + squaresList);List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);System.out.println("列表: " +integers);System.out.println("列表中最大的数 : " + getMax(integers));System.out.println("列表中最小的数 : " + getMin(integers));System.out.println("所有数之和 : " + getSum(integers));System.out.println("平均数 : " + getAverage(integers));System.out.println("随机数: ");// 输出10个随机数Random random = new Random();for(int i=0; i < 10; i++){System.out.println(random.nextInt());}System.out.println("使用 Java 8: ");System.out.println("列表: " +strings);count = strings.stream().filter(string->string.isEmpty()).count();System.out.println("空字符串数量为: " + count);count = strings.stream().filter(string -> string.length() == 3).count();System.out.println("字符串长度为 3 的数量为: " + count);filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());System.out.println("筛选后的列表: " + filtered);mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));System.out.println("合并字符串: " + mergedString);squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());System.out.println("Squares List: " + squaresList);System.out.println("列表: " +integers);IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();System.out.println("列表中最大的数 : " + stats.getMax());System.out.println("列表中最小的数 : " + stats.getMin());System.out.println("所有数之和 : " + stats.getSum());System.out.println("平均数 : " + stats.getAverage());System.out.println("随机数: ");random.ints().limit(10).sorted().forEach(System.out::println);// 并行处理count = strings.parallelStream().filter(string -> string.isEmpty()).count();System.out.println("空字符串的数量为: " + count);}private static int getCountEmptyStringUsingJava7(List<String> strings){int count = 0;for(String string: strings){if(string.isEmpty()){count++;}}return count;}private static int getCountLength3UsingJava7(List<String> strings){int count = 0;for(String string: strings){if(string.length() == 3){count++;}}return count;}private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){List<String> filteredList = new ArrayList<String>();for(String string: strings){if(!string.isEmpty()){filteredList.add(string);}}return filteredList;}private static String getMergedStringUsingJava7(List<String> strings, String separator){StringBuilder stringBuilder = new StringBuilder();for(String string: strings){if(!string.isEmpty()){stringBuilder.append(string);stringBuilder.append(separator);}}String mergedString = stringBuilder.toString();return mergedString.substring(0, mergedString.length()-2);}private static List<Integer> getSquares(List<Integer> numbers){List<Integer> squaresList = new ArrayList<Integer>();for(Integer number: numbers){Integer square = new Integer(number.intValue() * number.intValue());if(!squaresList.contains(square)){squaresList.add(square);}}return squaresList;}private static int getMax(List<Integer> numbers){int max = numbers.get(0);for(int i=1;i < numbers.size();i++){Integer number = numbers.get(i);if(number.intValue() > max){max = number.intValue();}}return max;}private static int getMin(List<Integer> numbers){int min = numbers.get(0);for(int i=1;i < numbers.size();i++){Integer number = numbers.get(i);if(number.intValue() < min){min = number.intValue();}}return min;}private static int getSum(List numbers){int sum = (int)(numbers.get(0));for(int i=1;i < numbers.size();i++){sum += (int)numbers.get(i);}return sum;}private static int getAverage(List<Integer> numbers){return getSum(numbers) / numbers.size();}
}

输出结果如下:

使用 Java 7:
列表: [abc, , bc, efg, abcd, , jkl]
空字符数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
平方数列表: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9
随机数:
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
使用 Java 8:
列表: [abc, , bc, efg, abcd, , jkl]
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数:
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
空字符串的数量为: 2

这篇主要讲述的是stream的 count,anyMatch,allMatch,noneMatch操作,我们先看下函数的定义

    long count();  boolean anyMatch(Predicate<? super T> predicate);  boolean allMatch(Predicate<? super T> predicate);  boolean noneMatch(Predicate<? super T> predicate);
  • count方法,跟List接口的size一样,返回的都是这个集合流的元素的长度,不同的是,流是集合的一个高级工厂,中间操作是工厂里的每一道工序,我们对这个流操作完成后,可以进行元素的数量的和;
  • anyMatch表示,判断的条件里,任意一个元素成功,返回true
  • allMatch表示,判断条件里的元素,所有的都是,返回true
  • noneMatch跟allMatch相反,判断条件里的元素,所有的都不是,返回true

我们来看下代码:

package com.pak2;import java.util.Arrays;
import java.util.List;public class StreamTest {public static void main(String[] args) {List<String> list = Arrays.asList("张三", "李四", "王五", "马六9");long count = list.stream().filter(m -> m.length() == 2).count();boolean allMatch = list.stream().allMatch(m -> m.equals("张三"));boolean allMatch1 = list.stream().allMatch(m -> m.length() == 2); // 长度是否都等于2System.out.println("count = "+count);System.out.println("allMatch = "+allMatch);System.out.println("allMatch1 = "+allMatch1);boolean anyMatch = list.stream().anyMatch(m -> m.equals("张三"));boolean anyMatch1 = list.stream().anyMatch(m -> m.equals("张0"));System.out.println("anyMatch = "+anyMatch);System.out.println("anyMatch1 = "+anyMatch1);boolean noneMatch = list.stream().noneMatch(m -> m.equals("张三"));boolean noneMatch1 = list.stream().noneMatch(m -> m.equals("张0"));System.out.println("noneMatch = "+noneMatch);System.out.println("noneMatch1 = "+noneMatch1);}
}

输出如下:

Stream流都是一些熟能生巧的处理,有时间多瞄瞄JDK8的帮助文档,看看API介绍就会用了。此处说一个小坑。

package com.pak2;import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;public class StreamTest {public static void main(String[] args) {List<String> list = Arrays.asList("张三", "李四", "王五", "马六9");// 此处我们统一创建一个streamStream<String> stream = list.stream();long count = stream.filter(m -> m.length() == 2).count();boolean allMatch = stream.allMatch(m -> m.equals("张三"));boolean allMatch1 = stream.allMatch(m -> m.length() == 2); // 长度是否都等于2System.out.println("count = "+count);System.out.println("allMatch = "+allMatch);System.out.println("allMatch1 = "+allMatch1);}
}

运行程序,报错如下:

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
    at java.util.stream.ReferencePipeline.allMatch(ReferencePipeline.java:454)
    at com.pak2.StreamTest.main(StreamTest.java:15)

Process finished with exit code 1

这段报错的意思就是说一个stream只可以使用一次,不可以重复使用。

总结:

Stream API的出现,使得我们可以使用流来处理集合,代码优雅而又整洁。Stream API功能强大,拥有一系列的功能丰富,可以通过阅读JDK帮助文档多加学习。

总结:

JDK8提供了很多新特性,限于篇幅,我们只总结了相关性比较大的三个特性,其余新特性在合适的时候,另行起一篇博客来学习总结吧。

由于本文是一个总结性质的文章,所以相关的文章已经由多位大神详细总结,本博客的总结站在了巨人的肩膀上。参考文献如下:

http://www.runoob.com/java/java8-new-features.html

https://www.cnblogs.com/pikachu-zhaof/p/9724826.html

https://www.cnblogs.com/wenbronk/p/7300544.html

https://blog.csdn.net/qq_28410283/article/details/80783946

https://www.cnblogs.com/xingzc/p/6002873.html

再次鸣谢....                                                                                         2019.2.24夜. 北京

如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,我会持续更新,如果有什么问题,可以进群366533258一起交流学习哦~

JDK8新特性的学习总结相关推荐

  1. JDK8新特性知识点总结

    一个简洁的博客网站:http://lss-coding.top,欢迎大家来访 学习娱乐导航页:http://miss123.top/ 1. Open JDK 和 Oracle JDK Java 由 S ...

  2. 【JDK8新特性】之Lambda表达式

    目录 Lambda表达式 1. 需求分析 2.Lambda表达式初体验 3. Lambda的语法规则 3.1 Lambda练习1 3.2 Lambda练习2 4. @FunctionalInterfa ...

  3. JDK8新特性详解Lambda、StreamAPI、Optional等

    JDK8学习笔记 学习视频地址:https://www.bilibili.com/video/BV1k64y1R7sA 操作代码:https://gitee.com/rederic/study-jdk ...

  4. 集合框架,JDK8新特性

    一.集合框架 1.为什么会有集合? 集合和数组都是java中提供的可以用来存储多个数据的一种容器.由于数组类型特点是存储同一类型的元素且长度固定,可以存储基本数据类型值.为了满足现实需求, Java中 ...

  5. JDK8新特性(三):集合之 Stream 流式操作

    1.Stream流由来 首先我们应该知道:Stream流的出现,主要是用在集合的操作上.在我们日常的工作中,经常需要对集合中的元素进行相关操作.诸如:增加.删除.获取元素.遍历. 最典型的就是集合遍历 ...

  6. JDK8新特性(五):JDK8时间日期API

    本文目录: 前言 1.旧版日期时间API存在的问题 2.新日期时间 API 介绍 3.用法介绍 1.JDK8 日期和时间类 2.JDK8 日期时间格式化与解析 3.JDK8 Instant 类 4.J ...

  7. 反射、注解、动态代理、JDK8新特性

    反射.注解.动态代理.JDK8新特性 第一章.反射 1.类的加载 源文件--通过javac编译-->字节码文件---通过Java命令(通过ClassLoader)--->JVM运行字节码文 ...

  8. JDK8 新特性流式数据处理

    在学习JDK8新特性Optional类的时候,提到对于Optional的两个操作映射和过滤设计到JDK提供的流式出来.这篇文章便详细的介绍流式处理: 一. 流式处理简介 流式处理给开发者的第一感觉就是 ...

  9. JDK8新特性相关知识讲解汇总

    以下是博主本人对jdk8相关新知识的学习以及讲解的汇总,如果对你帮助可以多多点赞和关注我哦~ (1)JDK8新特性-Lambda表达式详细介绍以及应用 (2)JDK8 关于中断线程的总结 (3)JDK ...

最新文章

  1. NFV技术本质是强调网络功能的软硬件同化能力,实现网络价值由硬件向软件的前移
  2. Android 开发之 ---- bootloader (LK)
  3. 渗透操作系统——【靶场实战训练营】快来看看有没有你需要的
  4. Redis _面试经典
  5. 一行 Python 代码轻松构建树状热力图
  6. oracle删除定义变量,Oracle存储过程,临时表的创建、删除,变量的定义和使用
  7. python自带sqlite库_Python标准库之sqlite3使用实例
  8. Python使用tkinter编写图片浏览程序
  9. 在SQL Server中设置最大并行度的不同方法
  10. Effective系列经典著作,铺就程序员殿堂之路
  11. scanf()正则表达式的使用
  12. java 汉字区位码表_汉字编码解析
  13. Hive实现笛卡尔积
  14. 微软雅黑字体包替换XP的宋体(附下载)
  15. Ubuntu18.04 搜狗输入法安装(史上最好用的输入法安装方法)
  16. 定时器之计时(时间的转换)
  17. 怎样恢复计算机的开机桌面,电脑系统崩溃如何找回桌面文件?
  18. 参考文献格式国家标准GB T7714-2015
  19. 京东2017校园招聘Android研发工程师编程题(二):幸运数
  20. 0~6岁儿童不同时期微量元素含量的结果分析

热门文章

  1. matlab的许可证文件路径,网络许可证文件 - MATLAB Simulink - MathWorks 中国
  2. 突发奇想的代码,根据出生日期查年龄哈哈
  3. python bytes decode_Python3 bytes.decode()方法
  4. 关于在内网穿透时如何使用X11的问题解决
  5. 暗黑百科全书中英文对照打印版
  6. 【GDI】 GDI与GDI+
  7. 苹果关闭了iOS13.3系统的更新/屏蔽iOS13系统更新方法/官方爆料新款iPhone无刘海...
  8. Go语言实现邮箱验证/邮件发送
  9. HTML 视频插入(利用优酷视频分享形成的通用代码)
  10. aac模式_AAC的完整形式是什么?