Java 8之新特性详解
Java8 新特性
- 1. Java8新特性简介
- 2. Java8新特性好处
- 3. Lambda表达式
- 3.1 Lambda表达式的使用
- 3.1.1 语法格式一:无参,无返回值
- 3.1.2 语法格式二:需要一个参数,但是没有返回值
- 3.1.3 语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为“类型推断”
- 3.1.4 语法格式四:Lambda若只需要一个参数时,参数 的小括号可以省略
- 3.1.5 语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且有返回值
- 3.1.6 语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
- 4. Java内置的4大核心函数式接口
- 4.1 Consummer 消费行接口
- 4.2 Predicate 断定型接口
- 5. 方法引用的使用
- 5.1 情况一:对象::实例方法
- 5.2 情况二:类::静态方法
- 5.3 情况三:类::实例方法(有难度)
- 6. 构造器引用
- 7. 数组引用
- 8. Stream API
- 8.1 为什么要使用Stream API
- 8.2 什么是Stream
- 8.3 Stream操作的三个步骤
- 8.4 Stream的创建方式
- 8.4.1 创建Stream方式一:通过结合
- 8.4.2 创建Stream方式二:通过数组
- 8.4.3 创建Stream方式三:Stream.of
- 8.4.4 创建Stream方式四:创建无限流
- 8.5 Stream 的中间操作
- 8.5.1 筛选与切片
- 8.5.2 映射
- 8.5.3 排序
- 8.6 终止操作
- 8.6.1 匹配与查找
- 8.6.2 规约
- 8.6.3 收集
- 9. Optional类
1. Java8新特性简介
2. Java8新特性好处
- 速度更快
- 代码更少(增加了新特性Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常:Optional
- Nashron引擎,允许在JVM上运行JS应用
3. Lambda表达式
3.1 Lambda表达式的使用
- 举例: ( o1, o2) -> Integer.compare(o1,o2);
- 格式:
-> :lambda操作符 或箭头操作符
->左边:lambad形参列表,(其实就是接口中的抽象方法的形参列表)
->右边:lambda体 (其实就是重写的抽象方法的方法体) - lambda表达式使用: (分6种情况)
总结:->左边,lambda形参列表的参数类型可以省略(类型推断),
如果lambda形参列表只有一个参数,其一对()小括号也可以省略
如果有没有或这有2个以上的,就不要省了
->右边:lambda应该使用一对{}包裹,如果lambda体只有一条执行语句(可能是return语句)
可以省略这一对{}和return关键字 - lambda表达式本质:作为函数式接口的实例
- 如果一个接口中,只声明了一个抽象方法,则此接口就成为函数式接口
- 所以以前用匿名实现类表示的,现在都可以用lambda表达式来写。
3.1.1 语法格式一:无参,无返回值
// 语法格式一,无参,无返回值public static void test1(){Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("我爱北京故宫");}};r1.run();//LambdaRunnable r2 = () -> {System.out.println("我爱北京天安门");};r2.run();}
3.1.2 语法格式二:需要一个参数,但是没有返回值
// 语法格式二,需要一个参数,但是没有返回值public static void test2(){Consumer<String> con = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};con.accept("谎言和誓言区别是什么呢?");System.out.println("****************************");//LambdaConsumer<String> con2 = (String s) -> {System.out.println(s);};con2.accept("一个是听的人当真了,一个是说的人当真了");}
3.1.3 语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为“类型推断”
//语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为“类型推断”public static void test3(){Consumer<String> con2 = (String s) -> {System.out.println(s);};con2.accept("一个是听的人当真了,一个是说的人当真了");Consumer<String> con3 = (s) -> {System.out.println(s);};con3.accept("一个是听的人当真了,一个是说的人当真了");//同样的效果ArrayList<String> list = new ArrayList<>();int [] arr = new int[]{1,2,3};int [] bb = {1,2,3};}
3.1.4 语法格式四:Lambda若只需要一个参数时,参数 的小括号可以省略
//语法格式四:Lambda若只需要一个参数时,参数 的小括号可以省略public static void test4 (){Consumer<String> con3 = (s) -> {System.out.println(s);};con3.accept("一个是听的人当真了,一个是说的人当真了");Consumer<String> con4 = s -> {System.out.println(s);};con4.accept("一个是听的人当真了,一个是说的人当真了");}
3.1.5 语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且有返回值
//语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且有返回值public static void test5(){Comparator<Integer> com1= new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);}};System.out.println(com1.compare(11,12));System.out.println("**************");Comparator<Integer> com2 = (o1, o2) -> {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);};System.out.println(com2.compare(11,12));}
3.1.6 语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
//语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略public static void test6(){Comparator<Integer> com2 = (o1,o2) -> {return o1.compareTo(o2);};System.out.println(com2.compare(11,12));System.out.println("**************");Comparator<Integer> com3 = (o1,o2) -> o1.compareTo(o2);System.out.println(com3.compare(11,12));}
同样的,第四种可以省略大括号{}
public static void test7(){Consumer<String> con4 = s -> {System.out.println(s);};con4.accept("一个是听的人当真了,一个是说的人当真了");System.out.println("**************");Consumer<String> con5 = s -> System.out.println(s);con5.accept("一个是听的人当真了,一个是说的人当真了");}
4. Java内置的4大核心函数式接口
- Consummer 消费行接口,用途:对类型为T的对象应用操做,包含方法:void accept(T t)
void accept(T t) - Supplier 供给型接口,用途:返回类型为T的对象,包含方法:T get()
T get() - Function 函数式接口 用途:对类型为T的对象应用操作,并返回结果。结果是R
R apply(T t) 类型的对象。包含方法:R apply(T t) - Predicate 断定型接口 用途:确定类型为T的对象是否满足某约束,并返回boolean值。包含方法
boolean test(T t) boolean test
4.1 Consummer 消费行接口
public static void test1 (){happyTime(500, new Consumer<Double>() {@Overridepublic void accept(Double aDouble) {System.out.println("学习太累了,去天上人间消费:" + aDouble);}});System.out.println("************************");happyTime(400,money -> System.out.println("消费:" + money));}public static void happyTime(double money, Consumer<Double> con){con.accept(money);}
4.2 Predicate 断定型接口
public static void test2(){List<String> list = Arrays.asList("北京","南京","天津","普京");ArrayList<String> filterStrs = filterString(list, new Predicate<String>() {@Overridepublic boolean test(String s) {return s.contains("京");}});System.out.println(filterStrs);//filterStrs.stream().forEach(System.out::println);System.out.println("****************************");ArrayList<String> filterStrs1 = filterString(list,s -> s.contains("京"));System.out.println(filterStrs1);}//根据给顶的规则,过滤集合中的字符串。此规则由Predicate的方法决定public static ArrayList<String> filterString (List<String> list, Predicate<String> pre){ArrayList<String> filterList = new ArrayList<>();for (String str:list){if (pre.test(str)){filterList.add(str);}}return filterList;}
5. 方法引用的使用
- 使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
- 方法引用:本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。
- 使用格式:类(或者对象)::方法名
- 具体非为如下的三种情况:
1.对象::非静态方法
2.类::静态方法
3.类::非静态方法 - 方法引用的使用要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的形参列表和返回值类型相同。针对1和2
5.1 情况一:对象::实例方法
////Consumer中的void accept(T t)//PrintStream中的void println(T t)public static void test1 (){Consumer<String> con1 = str -> System.out.println(str);con1.accept("北京");System.out.println("******************************");PrintStream ps = System.out;Consumer<String> con2 = ps::println;con2.accept("上海");}
public static void test2(){Employee emp = new Employee(1000,"longxi",23,1000);Supplier<String> sup1 = () -> emp.getName();System.out.println(sup1.get());System.out.println("******************************");Supplier<String> sup2 = emp::getName;System.out.println(sup2.get());}
5.2 情况二:类::静态方法
//情况二:类::静态方法//Comparator中的 int compare(T t1,T t2)//Integer中的 int compare(T t1,T t2)public static void test3(){Comparator<Integer> com1 = (t1,t2) ->Integer.compare(t1,t2);System.out.println(com1.compare(11,21));System.out.println("******************************");Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(9,12));}public static void test4(){Function<Double, Long> func1 = new Function<Double, Long>() {@Overridepublic Long apply(Double aDouble) {return Math.round(aDouble);}};System.out.println("******************************");Function<Double, Long> func2 = d -> Math.round(d);System.out.println(func2.apply(12.3));Function<Double, Long> func3 = Math::round;System.out.println(func3.apply(13.6));}
5.3 情况三:类::实例方法(有难度)
// 情况三:类::实例方法(有难度)// Comparator中的 int compare(T t1,T t2)// String中的int t1.compareTo(t2)// 如果是2个参数,第1个参数是作为里面方法的调用者出现的,这种情况就可以用public static void test5(){Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc","abd"));System.out.println("******************************");Comparator<String> com2 = String :: compareTo;System.out.println(com2.compare("abda","fdasfe"));}// BiPredicate中的boolean test(T t1,T t2)// String 中的boolean t1.equals(t2)public static void test6(){BiPredicate<String,String> pre1 = (s1, s2)->s1.equals(s2);System.out.println(pre1.test("fasfe","fegege"));System.out.println("******************************");BiPredicate<String,String> pre2 = String ::equals;System.out.println(pre2.test("abc","abd"));}// Function 中的apply(T t1)// Employee 中的 String getNamepublic static void test7(){System.out.println("************test7******************");Employee emp = new Employee(1000,"longxi",23,1000);Function<Employee,String> func1 = e -> e.getName();System.out.println(func1.apply(emp));System.out.println("******************************");Function<Employee,String> func2 = Employee :: getName;System.out.println(func2.apply(emp));}
6. 构造器引用
- 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
- 抽象方法的返回值类型即为构造器所属的类的类型
构造方法
public Employee (){System.out.println("Employee()-------");}
//构造器引用//Supplier中的get()//Employee的空参构造器:Employee()public static void test1 (){Supplier<Employee> sup = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};System.out.println(sup.get());System.out.println("******************************");Supplier<Employee> sup1 = () -> new Employee();System.out.println(sup1.get());System.out.println("******************************");Supplier<Employee> sup2 = Employee::new;System.out.println(sup2.get());}
// Function中的apply(T t)public static void test2(){Function<Integer,Employee> func1 = id -> new Employee(id);Employee apply = func1.apply(1000);System.out.println(apply);System.out.println("******************************");Function<Integer,Employee> func2 = Employee::new;Employee apply1 = func2.apply(1002);System.out.println(apply1);}
// BiFunction中的apply(T t, U u )public static void test3(){BiFunction<Integer,String,Employee > func1 = (id,name) ->new Employee(id,name);System.out.println(func1.apply(1002,"longxi2"));System.out.println("******************************");BiFunction<Integer,String, Employee> func2 = Employee::new;System.out.println(func2.apply(1002,"longxi3"));}
7. 数组引用
可以把数组看成是一个特殊的类,则写法和构造引用一致。
// 数组引用// Function中的apply(T t)public static void test4(){Function<Integer, String[]> func1 = Length -> new String[Length];System.out.println(Arrays.toString(func1.apply(5)));System.out.println("******************************");Function<Integer,String[]> func2 = String[]::new;System.out.println(Arrays.toString(func2.apply(10)));}
8. Stream API
Stream API提供了一种高效且易于使用的处理数据方式。
类似于使用SQL执行数据库查询。
8.1 为什么要使用Stream API
- 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Redis等,而这些NoSql的数据就需要Java层面去做处理。
- Stream 和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
8.2 什么是Stream
Stream 是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。
集合讲的数据,Stream讲的是计算
注意:
- Stream 自己不会存储元素。
- Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream
- Stream操作时延迟执行。这意味这他们会等到需要结果的时候才执行。
8.3 Stream操作的三个步骤
- 创建Stream
一个数据源(如:集合、数组),获取一个流 - 中间操作
一个中间操作链,对数据源进行处理 - 终止操作
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
8.4 Stream的创建方式
8.4.1 创建Stream方式一:通过结合
// 创建Stream方式一:通过结合public static void test1(){List<Employee> employees = EmployeeData.getEmployees();// 返回一个顺序流Stream<Employee> stream = employees.stream();// 返回一个并行流 多个线程Stream<Employee> employeeStream = employees.parallelStream();}
8.4.2 创建Stream方式二:通过数组
// 创建Stream方式二:通过数组public static void test2(){int [] arr = new int[]{1,2,3,4};IntStream stream = Arrays.stream(arr);Employee employee = new Employee(1002, "longx");Employee employee2 = new Employee(1002, "longx2");Employee[] arr1 = new Employee[]{employee,employee2};Stream<Employee> stream1 = Arrays.stream(arr1);}
8.4.3 创建Stream方式三:Stream.of
// 第三种方式 Stream.ofpublic static void test3(){Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);}
8.4.4 创建Stream方式四:创建无限流
// 第四种方式 创建无限流public static void test4(){// 迭代Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);// 生成Stream.generate(Math::random).limit(10).forEach(System.out::println);}
8.5 Stream 的中间操作
8.5.1 筛选与切片
public static void test1(){//过滤List<Employee> list = EmployeeData.getEmployees();// 工资大于7000list.stream().filter(e ->e.getSalary() >7000).forEach(System.out::println);// 取前三条System.out.println();list.stream().limit(3).forEach(System.out::println);// 跳过前3条System.out.println();list.stream().skip(3).forEach(System.out::println);// 去重System.out.println();list.add(new Employee(1010,"刘强东",40, 8000));list.add(new Employee(1010,"刘强东",40, 8000));list.add(new Employee(1010,"刘强东",40, 8000));list.add(new Employee(1010,"刘强东",40, 8000));System.out.println(list);list.stream().distinct().forEach(System.out::println);}
8.5.2 映射
//映射public static void test2(){//Map 相当与add 集合里套集合List<String> list = Arrays.asList("aa","bb","cc","dd");list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);//获取员工姓名长度大于3的员工姓名List<Employee> employees = EmployeeData.getEmployees();Stream<String> nameStream = employees.stream().map(e -> e.getName());nameStream.filter(name -> name.length() > 3).forEach(System.out::println);// 练习2Stream<Stream<Character>> streamStream = list.stream().map(StreamTest1::fromStringToStream);streamStream.forEach(s ->{s.forEach(System.out::println);});System.out.println("flatMap");//flatMap 相当于addAll,集合打散了Stream<Character> characterStream = list.stream().flatMap(StreamTest1::fromStringToStream);characterStream.forEach(System.out::println);}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例public static Stream<Character> fromStringToStream(String str){ArrayList<Character> list = new ArrayList<>();for (Character c : str.toCharArray()){list.add(c);}return list.stream();}
8.5.3 排序
//排序public static void test4(){// sorted() 自然排序List<Integer> list = Arrays.asList(12, 45, 78, 32, -78, 797);list.stream().sorted().forEach(System.out::println);//会报异常,因为没有实现Comparable接口//List<Employee> employees = EmployeeData.getEmployees();//employees.stream().sorted().forEach(System.out::println);// sorted(Comparator com) 定制排序List<Employee> employees = EmployeeData.getEmployees();employees.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);employees.stream().sorted((e1,e2)->{int value = Integer.compare(e1.getAge(),e2.getAge());if (value!= 0){return value;} else {return Double.compare(e1.getSalary(),e2.getSalary());}}).forEach(System.out::println);}
8.6 终止操作
8.6.1 匹配与查找
/*** @author LongXi* @create 2021-07-12 20:22*/
public class StreamTest2 {public static void main(String[] args) {test1();test2();}// 匹配与查找public static void test1(){List<Employee> list = EmployeeData.getEmployees();// allMath//练习:是否所有员工年龄都大于18boolean allMatch = list.stream().allMatch(e -> e.getAge() > 18);System.out.println(allMatch);//anyMatch// 练习:是否存在员工工资大于10000boolean anyMatch = list.stream().anyMatch(e -> e.getSalary() > 10000);System.out.println(anyMatch);//noneMatch// 是否存在员工姓“雷”boolean noneMatch = list.stream().noneMatch(employee -> employee.getName().startsWith("雷"));System.out.println(noneMatch);//findFirst// 返回第一个元素Optional<Employee> first = list.stream().findFirst();System.out.println(first);//findAny// 返回当前流中任意一个元素//Optional<Employee> any = list.stream().findAny();Optional<Employee> any = list.stream().parallel().findAny();System.out.println(any);}public static void test2 (){List<Employee> list = EmployeeData.getEmployees();// count// 工资大于5000的员工个数long count = list.stream().filter(employee -> employee.getSalary() > 5000).count();System.out.println(count);//max// 返回最高的工资Optional<Double> max = list.stream().map(e -> e.getSalary()).max(Double::compare);System.out.println(max);//min// 返回工资最低的员工Optional<Employee> min = list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(min);//forEach - 内部迭代list.stream().forEach(System.out::println);//使用结合遍历list.forEach(System.out::println);}
}
8.6.2 规约
public static void test3(){// reduce// 计算1-10的自然数的和List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);System.out.println(list.stream().reduce(0,Integer::sum));// 计算工资所有员工的工资总和List<Employee> list1 = EmployeeData.getEmployees();Stream<Double> rStream = list1.stream().map(Employee::getSalary);Optional<Double> reduce = rStream.reduce(Double::sum);//Optional<Double> reduce1 = rStream.reduce((e1,e2)->e1+e2);System.out.println(reduce);//System.out.println(reduce1);}
8.6.3 收集
//collect//查找工资大于6000的员工,结果返回一个list或者setList<Employee> list = EmployeeData.getEmployees();List<Employee> employeeList = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());employeeList.forEach(System.out::println);System.out.println();Set<Employee> set = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());set.forEach(System.out::println);
9. Optional类
boy类
/*** @author LongXi* @create 2021-07-12 22:19*/
public class Boy {private Girl girl;@Overridepublic String toString() {return "Boy{" +"girl=" + girl +'}';}public Girl getGirl() {return girl;}public void setGirl(Girl girl) {this.girl = girl;}public Boy(Girl girl) {this.girl = girl;}
}
girl类
/*** @author LongXi* @create 2021-07-12 22:19*/
public class Girl {private String name;public Girl() {}@Overridepublic String toString() {return "Girl{" +"name='" + name + '\'' +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public Girl(String name) {this.name = name;}
}
测试类
private static void test1 (){// Optional.of 必须保证t是非空的Girl girl = new Girl();Optional.of(girl);//Optional.ofNullable 可以为空的girl = null;Optional<Girl> optionalGirl = Optional.ofNullable(girl);System.out.println(optionalGirl);// orElseGirl longxi = optionalGirl.orElse(new Girl("longxi"));System.out.println(longxi);}
测试结果
// 以前写法public static String getGirlName(Boy boy){return boy.getGirl().getName();}// 优化写法public static String getGirlName1(Boy boy){if (boy != null){Girl girl = boy.getGirl();if (girl!= null){return girl.getName();}}return null;}// 使用Optional优化写法public static String getGirlName2(Boy boy){Optional<Boy> boy1 = Optional.ofNullable(boy);Boy boy2 = boy1.orElse(new Boy(new Girl("longxi1")));Girl girl = boy2.getGirl();Optional<Girl> girl1 = Optional.ofNullable(girl);Girl longxi2 = girl1.orElse(new Girl("longxi2"));return longxi2.getName();}private static void test3(){Boy boy = new Boy();String girlName = getGirlName1(boy);boy = null;String girlName2 = getGirlName2(boy);System.out.println(girlName2);boy = new Boy();girlName2 = getGirlName2(boy);System.out.println(girlName2);boy = new Boy(new Girl("longxi3"));girlName2 = getGirlName2(boy);System.out.println(girlName2);}
输出结果
Java 8之新特性详解相关推荐
- Java EE 8的五大新特性详解
Java EE 8的五大新特性详解 2018.4.3 版权声明:本文为博主chszs的原创文章,未经博主允许不得转载. Java EE 8带来了很多新特性,其中最好的新特性有下面五个. 备受期待的Ja ...
- Java基础学习总结(33)——Java8 十大新特性详解
Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...
- 还在用JDK6的同学,来看看JDK13新特性详解吧
点击上方"搜云库技术团队"关注,选择"设为星标" 回复"面试题"或"1024"获取 4T 学习资料 在 JDK 版本的世 ...
- java11 新特性 详解
为什么80%的码农都做不了架构师?>>> 引言: 点击-->java10 新特性 详解 点击-->java9 新特性 详解 点击-->java8 新特性 详解 ...
- Java9 新特性 详解
目录 Java9 新特性 详解 1.Java9新特性之---目录结构 2.Java9新特性之---JShell工具 3.Java9新特性之---模块化 4.Java9新特性之---多版本兼容Jar包 ...
- java8-stream新特性详解及实战
Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了.为此, ...
- Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验
Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...
- 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高...
第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...
- oracle dataguard详解,Oracle 19c 新特性详解:DataGuard 中ADG的自动DML重定向
Oracle 19c 新特性详解:DataGuard 中ADG的自动DML重定向 在前面的文章<Oracle 19c 十大新特性一览>中,我们曾经提到 Oracle 19c的一个重要增强, ...
最新文章
- Mybatis的各种查询功能
- 修改mysql参数_mysql动态修改参数
- linux下的nginx+php+mysql
- JQuery快速入门-选择器
- Java泛型中的子类型化
- ms sql 带自增列 带外键约束 数据导入导出
- (72)Verilog HDL系统函数和任务:$display
- 第16 17章节-Python3.5-Django知识点整理 15
- 关于jstl EL用法的注意点(java.lang.NumberFormatException: For input string: userName)
- 可空类型 (C# 编程指南)
- Qt:多线程--子线程间通讯
- C++学习笔记(达内视频版)
- Chrome驱动对应chrome浏览器版本
- 中文输入纠错任务整理
- java 人脸活体检测_人脸识别活体检测测试案例
- 批处理命令——bat文件创建和基本命令语法
- DPDK ipv4 ip分片与重组
- 安吉县人力资源和社会保障局数据中心容灾备份项目
- 如何清理Linux跟下的垃圾文件
- centos7.1 修改selinux相关机制后出现开机失败,报错faild to load selinux policy freezing