科普文:Java8、9、10、11的新特性

概叙

详细8、9、10、11的新特性见官方的What's New

Home: Java Platform, Standard Edition (Java SE) 8 Release 8

What's New in JDK 8

Oracle JDK 9 Documentation

Java Platform, Standard Edition What’s New in Oracle JDK 9, Release 9

JDK 10 Documentation

JDK 11 Documentation - Home

Java8

Lambda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。使用它可以写出更简洁,更灵活的的代码。作为一种观念更紧凑的代码风格,使Java的语言表达能力得到了提升。

//Lambda表达式的使用举例
@Test
public void test1(){
Runnable r1 = new Runnable(){
@Override
public void run(){
System.out.println("测试lambda")
}
}
r1.run();
//使用lambda
Runnable r2 = ()->System.out.println("我爱北京天安门");
r2.run();
}

Lambda表达式的使用
1.举例:(o1,o2) -> Integer.compare(o1,o2);
2.格式:
->:lambda操作符 或箭头操作符
->左边:lambda形参列表(其实就是接口中的抽象方法的形参列表)
->右边:lambda体(其实就是重写的抽象方法的方法体)
3.Lambda表达式的使用:(分为6种情况)
语法格式一:无参,无返回值

Runnable r1 = () ->{System.out.println("hello Lambda!")};

语法格式二:Lambda需要一个参数,但是没有返回值

Consumer<String> con = (String str)->{System.out.println(str)};

语法格式三:数据类型可以省略,因为可由编译器推断得出,称为类型推断

Consummer<String> con = (str)->{System.out.println(Str);};

语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略

Consumer<String> con = str -> {System.out.println(str);};

语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值

Comparator<Integer> com = (x,y)->{
System.out.print("实现函数时接口方法!");
return Integer.compare(x,y);
}

语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略

Comparator<Integer> com = (x,y)->Integer.compare(x,y);

总结:
->左边:Lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
->右边:Lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return 语句),可以省略这一对{}和return关键字

4.Lambda表达式的本质:作为函数式接口的实例

函数式接口

如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口,可以使用FunactionalInterface检验是否属于函数式接口
匿名实现类标识的都可以用Lambda表达式来写

//定义一个函数式接口
@FunctionalInterface
public interface MyInterface{
void method1();
}

Java内置的四大核心函数式接口:

函数式接口参数类型返回类型用途
Consumer<T>消费型接口Tvoid对类型为T对象应用操作,包含方法:void accept(T t);
Supplier<T>供给型接口T返回类型为T的对象:包含方法:T get();
Function<T,R>函数型接口TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象,包含方法:R apply(T t)
Predicate<T>Tboolean确定类型为T的对象是否满足某约束,并返回boolean值,包含方法:boolean test(T t)
@Test
public void test1(){
happTime(500, money->System.out.println("花费了"+money+"元,好开心"));
}
public void happyTime(double money,Consumer<Double> con){
con.accept(money);
}
@Test void test2(){
List<String> list = Arrays.asList("北京","南京","天津","东京","普京");
List<String> filterStr = filterString(list,s->s.contains("京"));
System.out.printn(filterStr);
}
//根据给定的规则, 过滤集合中的字符串,此规则由Predicate的方法决定
public List filterString(List<String>list,Predicate<String> pre){
ArrayList<String> filterList = new ArrayList<>();
for(String s : list){
if(pre.test(s)){
filterList.add(s);
}
}
return filterList;
}

方法引用和构造器引用

当要传递给Lambda体的操作,已经有实现的方法发,可以使用方法引用
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖
要求:实现接口的抽喜爱那个方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
格式:使用操作符"::"将类(或对象)与方法名分隔开来。
如下三种主要使用情况:
情况1:对象::实例方法名
情况2:类::静态方法名
情况3:类::实例方法名。
1.使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
2.方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例
3.方法引用使用的要求:要求接口种的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同。(针对情况1和2)

@Test
public void test1(){
PrintStream ps = System.out;
Consumer<String> con2 = ps::println;
con2.accept("beijing");
}
@Test
public void test2(){
Employee emp = new Employee(1001,"tom",23,5600);
Suppliper<Strijng> sup2 = emp::getName;
System.out.println(sup2.get);
}
@Test
public void test3(){
Comparator<Integer> com1 = Integer::compare;
System.out.println(com1.compare(11,12));
}
@Test
public void test5()){
Comparator<String> com1 = (s1,s2)->s1.compareTo(s2);
System.out.println(com1.compare("abc","abd"));
Comparator<String> com2 = String::compareTo;
System.out.println(com21.compare("abd","abc"));
}
@Test
public void test7(){
Employee employee = new Employee(1001,"jerry",23,50000);
Function<Employee,String> func1 = e->e.getName();
System.out.println(func1.apply(employee));
Function<Employee,String> func2 = Employee::getName;
System.out.println(func1.apply(employee));
}

构造器引用

和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
抽象方法的返回值类型即为构造器所属的类的类型

@Test
public void test1(){
Supplier<Employee> sup1 = ()->new Employee();
Supplier<Employee> sup2 = Employee::new;
Employee employee1 = sup1.get();
Employee employee2 = sup2.get();
}
@Test
public void test2(){
Function<Integer,Employee> func1 = id->new Employee(id);
Employee employee = func1.apply(1001);
System.out.println(employee);
Function<Integer,Employee> fun2 = Employee::new;
Employee employee1 = fun2.apply(1002);
}

数组引用

可以把数组看作是一个特殊的类,则写法与构造器引用一致

@Test
public void test4(){
Function<Integer,String[]>func1 = length ->new String[length];
String[] arr1 = func1.apply(5);
System.out.println(Arrays.toString(arr1));
Function<Integer,String[]> func2 = String[]::new;
String[] arr2 = func2.apply(5);
System.out.println(Arrays.toString(arr2));
}

Stream API

Stream API(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前位置对Java类库最好的补充,因为StreamAPI 可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用StreamAPI对集合数据进行操作,就类似使用SQL执行的数据库查询,也可以使用StreamAPI来并行执行操作。简言之,StreamAPI提供了以中高效且易于是哟个你的处理数据的方式。
NoSQL的数据(redis,MongDB)需要Java层面去处理
Stream 和 Collection 集合的区别:Collection是以中静态的内存数据结构,而Stream是有关计算的,前者主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
Stream到底是什么?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的事数据,Stream讲的是计算!”
Stream自己不会存储元素,Stream不会改变源对象,相反,他们回返回一个持有结果的新的Stream。Stream操作是延迟执行的。这意味着他们回等到需要结果的时候才执行。
Stream的操作的三个步骤
1-创建Stream
一个数据源(如:集合数组)获取一个流
2-中间操作
一个中间操作连,对数据源的数据进行处理
3-终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果,之后不会再被使用。
4.说明:
4.1一个中间操作链,对数据源的数据进行处理
4.2一旦执行终止操作,就执行中间操作链,并产生结果,之后不会再被使用。

//创建Stream方式一:通过集合
@Test
public void test1(){
List<Employee> employees = EmployeeData.getEmployees();
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream():返回一个并行流
}
//创建Stream方式二:通过数组
@Test
public void test2(){
//通过Arrays类的static<T> Stream<T> stream(T[] array):返回一个流
int[] arr = new int[]{1,2,3,4,5,6};
IntStream stream = Arrays.stream(arr);
Employee e1 = new Employee(1001,"Tom");
Employee e2 = new Employee(1002,"Jerry");
Stream<Employee> stream1 = Arrays.stream(arr1);
}
@Test
public void test3(){
//创建Stream方式三:通过Stream的of()
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
//创建Stream 方式四:
//迭代
//遍历前10个偶数
Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);
//生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}

Stream的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上出发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
1-筛选与切片

方法描述
filter(Predicate p)接受Lambda,从流中排除某些元素
distinct()筛选,通过流所生成的元素的hashCode()和equals()去除重复元素
limit(long maxSize截断流,使其元素不超过给定数量)
Skip(long n)跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n)互补
//1-筛选与切牌你
@Test
public void test1(){
List<Employee> list = EmployeeData.getEmployees();
//filter(Predicate p)——接收Lambda,从流中排除某些元素。
Stream<Employee> stream = list.stream();
stream.filter(e->e.getrSalary()>7000).forEach(System.out::println);
list.stream().limit(3).forEach(System.out::println);
list.stream().skip(3).forEach(System.out::println);
list.stream().distinct().forEach(System.out.println);
}

2-映射

方法描述
map(Function f)接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
map ToDouble(ToDoubleFunction n)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
map ToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
map ToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连成一个流
List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream().map(str->str.toUpperCase()).forEach(System.out::println);
//获取员工姓名长督促大于3的员工的姓名
List<Employee> employees = EmployeeDataa.getEmployees();
//employees.stream().map(e->e.getName());
Stream<String> stringStream = employees.stram().map(Employee::getName);
nameStream.filter(name->name.length()>3).forEach(System.out::println);
//
Stream<Stream<Character>> streamStream = list.stream().map(StreamApiTest1::fromStringToStream);
streamStream.forEach(s->{
s.forEach(System.out::print);
})
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
characterStream.forEach(System.out::print);
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}

3-排序

方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Compoarator com)产生一个新流,器中按比较器顺序排序
List<Integer> list = Arrays.stream(23,432,235,34,23,455,23324);
list.stream().sorted().forEach(System.out::print);
//Employee需要实现Comparable接口
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted().forEach(System.out.print);
employees.stream().sorted((e1,e2)->{
return Integer.compare(e1.getAge,e2.getAge)
}).forEach(System.out::print);

Stream的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void
流进行了终止操作后,不能在此使用。
1-匹配与查找

方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素的总个数
max(Comparator c)返回流中的最大值
min(Comparator c)返回流中的最小值
forEach(Consumer c)内部迭代
 
List<Employee> employees = EmployeeData.getEmployees();
boolean allMatch = employees.stream().allMatch(e->getAge()>18);
System.out.println(allMatch);
boolean anyMatch = employees.stream().anyMatch(e->getAge()>18);
System.out.println(anyMatch);
boolean noneMatch = employees.stream().noneMatch(e->getName().startsWith("张"));
System.out.println(noneMatch);
Optional<Employee> employee = employess.stream.findFirst();
System.out.println(employee);
Optional<Employee> findAny = employess.parallelStream().findAny();
System.out.println(findAny);
long count = employees.stream().filter(e->e.getSalary()>5000).count();
System.out.println(count);
Stream<Double> salaryStream = employees.stream().map(e->e.getSalarty());
Optional<Double> maxSalary = salaryStream.max(Double::compare);
System.out.print(maxSalary);
Optional<Employee> employee = employees.stream().min((e1,e2)->Double.compare(e1.getSalary,e2.getSalary));
System.out.println(employee);

2-归约

方法描述
reduce(T iden,BinaryOperator b)可以将流中元素反复结合起来,得到一个值,返回T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值,返回Optional<T>
 
//计算1-10的自然数的和
List<Integer> list = Arralys.toList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0,Integer::sum);
System.out.print(sum);
List<Employee> employees = EmployeeData.getEmployees();
Option<Double> sumMoney = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.print(sumMoney);

3-收集

方法描述
collect(Collector c)将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List,Set,Map)
另外,Collectors实用类提供了很多静态方法,可以方便的创建常见收集器实例。

image

List<Employee> employees = EmployeeData.getEmployees();
List<Employee> employeeList = employees.stream().filter(e->e.getSalary()>6000).collect(Collectors.toList());
employeeList.forEach(System.out::println);
 
List<Person> people = Arrays.asList(
new Person(1, "Alice"),
new Person(2, "Bob"),
new Person(3, "Charlie")
);
Map<Integer, Person> peopleById = people.stream()
.collect(Collectors.toMap(Person::getId, Function.identity()));
System.out.println(peopleById);

Optional 类

Optional<T> 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常
Optional提供很多有用的方法,这样我们就不用显式进行空值检测
创建Optional类对象的方法:

Optional.of(T t):创建一个Optional实例,t必须非空;
Optional.empty():创建一个空的Optional实例
Optional.ofNullable(T t):t可以为null

判断Option容其中上是否包含对象

bolean isPresent():判断是否包含对象
void ifPresent(Consumer<? super T> consumer):如果有值,就执行Comsumer接口的实现代码,并且该值会作为参数传给他

获取Optional容器的对象

T get():如果调用对象包含之,返回该值,否则跑一次
T orElse(T other):如果有值则将其返回,否则返回指定的other对象
T orELseGet(Supplier<? extends T> other): 如果有值将其返回,否则返回由Supplier接口实现提供的对象
T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

 
Girl girl = new Girl();
Option<Girl> optionGirl = Option.of(girl);
Option<gorl> optrionGirl1 = optionl.ofNullable(girl);
girl = null;
System.out.println(optionGirl1);
public String getGirlName(Boy boy){
//优化前
//return boy.getGirl().getName();
//if(boy!=null){
//Girl girl = boy.getGirl();
//if(girl!=null){
//return girl.getName();
//}
//}
//return null;
//优化后:
Optional<Boy> boyOptional = Optional.ofNullable(boy);
//T orElse(T other):如果有值则将其返回,否则返回指定的other对象
Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
Girl girl = boy1.getGirl();
Optional<Girl> girlOptional = Optional.ofNullable(girl);
//Girl1一定非空
Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
return girl1.getName();
}
Boy boy = null;
Boy boy = new Boy();
String girlName = getGirlName(boy);
System.out.println(girlName);

java9

语法改进:接口的私有方法

Java 8中规定接口中的方法除了抽象方法之外,还可以定义静态方法和默认方法。一定程度上,扩展了接口的功能,此时的接口更像是一个抽象类。
在Java 9中,接口更加的灵活和强大,连方法的权限修饰符都可以声明为private的了,此时方法将不会称为你对外暴露API的一部分。

 
public interface MyInterface{
//如下的三个方法修饰符都是public
void methodAbstract();
static void methodStatic(){
System.out.println("我是接口中的静态方法");
}
default void methodDefault(){
System.out.println("我是接口中的默认方法");
}
//jdk9中允许接口中定义私有的方法
private void methodPrivate(){
System.out.println("我是接口中的私有方法");
}
}
 
public class MyInterfaceImp implements MyInterface{
@Override
public void methodAbstract(){
}
@Override
public void methodDefault(){
System.out.println("实现类实现了接口中的默认方法")
}
public static void main(String[] args){
//接口中的静态方法只能由接口自己调用,接口的实现类不能调用接口的静态方法
MyInterface.methodStatic();
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.methodDefault();
//私有方法不能调用
//impl.methodPrivate();
}
}

钻石操作符使用升级

我们将能够与匿名实现类共同使用钻石操作符(diamond operator)在Java8中如下操作时会报错的:

 
Comparator<Object> com = new Comparator<>(){
@Override
public int compare(Object o1,Object o2){
return 0;
}
}

try语句

Java8中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过,如下例所示:

 
//java8中资源关闭操作
try(InputStreamReader reader = new InputStreamReader(System.in)){
//读取数据细节省略
}catch(IOException e){
e.printStackTrace();
}
//Java9中资源关闭操作
//此时的资源属性是常量
InputStreamReader reader = new InputStreamReader(System.in);
try(read){
//读取数据细节省略
}catch(IOException e){
e.printStackTrace();
}

String存储结构的变更

Java8用的是char[],java9用的是byte[]

集合工厂方法:创建只读集合

 
//java8的写法
List<String> namesList = new ArrayList<>();
namesList.add("joe");
namesList.add("Bob");
namesList.add("Bill");
namesList = Collections.unmodifiableList(nameList);
System.out.println(namesList);
//此时集合只是一个只读集合
List<Integer> list = Arrays.asLisst(1,2,3,4);
//java9
List<Integer> list11 = List.of(1,2,3,4,5);

InputStream加强

transferTo:可以用来将数据直接传输到OuptputStream,这是在处理原始数据流时非常常见的一种观念用法

 
ClassLoader c1 = this.getClass().getClassLoader();
try(InputStream is = c1.getResourceAsStream("hello.txt");OutputStream os = new FileOutPutStream("src\\hello.txt")){
is.transferTo(os);
}catch(IOException e){
e.printStackTrace();
}

增强的StreamAPI

 
//takeWhile()的使用:返回从开头开始的按照指定规则尽量多的元素
List<Integer> list = Arrays.asList(23,43,35,543,23,45,334);
list.stream().takeWhile(x->x<60).forEach(System.out::println);
//dropWhile()的使用:返回剩余的元素
list.stream().dropWhiele(x0>x<60).forEach(System.out::println);
//ofNullable()使用
//java8中Stream不能完全为null,否则会报空指针异常。而java9中的ofNullable方法允许我们创建一个单元素Stream,可以包含一个非空元素,也可以创建一个空的Stream
//of()参数中的多个元素,可以包含null值
Stream<Integer> stream1 = Stream.of(1,2,3,null);
stream1.forEach(System.out::println);
//of()参数不能只存储单个null值,否则报异常
//ofNullable():形参变量是可以为null值得单个元素
Integer i = 10;
i = null;
Stream<Integer> stream 3 = Stream.ofNullablle(i);
 
//java8
Stream.iterate(0,x->x+1).limit(10).forEach(System.out::print);
//java9 添加终止条件
Stream.iterate(0,x->x<100,x->x+1).forEach(System.out::println);

Optional获取Stream

 
List<String> list = new ArrayList<>;
list.add("Tom");
list.add("Jerry");
list.add("Tim");
Optional<List<String>> optional = Optional.ofNullable(list);
Stream<List<String>> stream = option.stream();
stream.flatMap(x->x.stream()).forEach(System.out::println);

java10 特性

局部变量类型推断

不适用得情况
初始值为null,方法引用,Lambda表达式,为数组静态初始化

 
var num = 10;
var list = new ArrayList<>(Integer);
for(var i : list){
System.out.println(i);
}

集合中新增copyOf(),用于创建一个只读的集合

 
var list1 = List.of("java","python","c");
var copy1 = List.copyOf(list1);
System.out.println(list1==copy1);//true
var list2 = new ArrayList<String>();
list2.add("aaa")
var copy2 = List.copyOf(list2);
System.out.print(list2==copy2);//false
//copyOf(Xxx coll):如果参数coll本身就是一个只读集合,则copyOf()返回值即为只读集合,如果参数coll不是一个只读集合,则copyOf()返回一个新的集合,这个集合是只读的

java11新特性:GC

String中新增的方法

isBank():判断字符串是否为空
strip():去除首尾空格
stripTrailing():去除尾部的空格
stripLeading():去除首部的空格
repeat():复制字符串
lines().count():行数统计

Optional加强

新增方法:
boolean isEmptly():判断value是否为空 11
ifPresentOrElse(Consumer<? super T> action,Runnable emptyAction):value非空执行参数1 功能,如果value为空执行参数2功能 9
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier:value非空,返回对应的Optional;value为空返回形参封装的Optional 9
Stream<T> stream():value非空,返回仅包含此value的Stream,否则返回一个空的Stream 9
T orElseThrow():value非空,返回value;否则抛异常NoSuchEmelmentException 10

 
var op = Optional.empty();
op = Optional.of("abc");
Optional<String> op1 = Optional.of("hello");
op.or(()->op1);

局部类型推断升级

 
//错误的形式:必须要有类型,可以加上var
//Consumer<String> con1 = (@Deprecated t)-> System.out.println(t.toUpperCase());
//正确的形式
//使用var的好处是在使用lambda表达式时给参数加上注解
Consumer<String> con2 = (@Deprecated var t) ->System.out.println(t.toUpperCase);

编译和运行合为一个 java javatest.java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/802508.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

美式键盘 QWERTY 布局的起源

注&#xff1a;机翻&#xff0c;未校对。 The QWERTY Keyboard Is Tech’s Biggest Unsolved Mystery QWERTY 键盘是科技界最大的未解之谜 It’s on your computer keyboard and your smartphone screen: QWERTY, the first six letters of the top row of the standard keybo…

launch4j和inno setup组合使用:保姆级教程【搬代码】

launch4j&#xff1a; 将jar包打成exe&#xff0c;并且将exe赋值.icon图片 此页面选择ico图片路径不要有汉字&#xff0c;不然报错 这个图没抓住用一下上一个文章的图&#xff0c;就是这个意思 查看结果&#xff1a; 下面使用inno Setup搞成安装包&#xff1a; 双击 点击…

从汇编层看64位程序运行——栈保护

大纲 栈保护延伸阅读参考资料 在《从汇编层看64位程序运行——ROP攻击以控制程序执行流程》中&#xff0c;我们看到可以通过“微操”栈空间控制程序执行流程。现实中&#xff0c;黑客一般会利用栈溢出改写Next RIP地址&#xff0c;这就会修改连续的栈空间。而编译器针对这种场景…

pip install安装第三方库 error: Microsoft Visual C++ 14.0 or greater is required

原因&#xff1a; 在windows出现此情况的原因是pip安装的库其中部分代码不是python而是使用C等代码编写&#xff0c;我们安装这种类型的库时需要进行编译后安装。 安装Microsoft C Build Tools软件&#xff0c;但这种方式对于很多人来说过于笨重。&#xff08;不推荐&#xf…

视图库对接系列(GA-T 1400)十九、视图库对接系列(级联)注册

背景 在上一章视图库对接系列(GA-T 1400)十八、视图库对接系列(级联)代码生成中我们已经把代码生成了,那怎么实现级联? 我们可以抓包看设备是怎么注册到我们平台的, 那我们就怎么实现就可以了。 实现 先看设备注册到我们服务端的包 步骤 注册我们可以参考视图库对接系列(…

【JVM实战篇】内存调优:内存问题诊断+案例实战

文章目录 诊断内存快照在内存溢出时生成内存快照MAT分析内存快照MAT内存泄漏检测的原理支配树介绍如何在不内存溢出情况下生成堆内存快照&#xff1f;MAT查看支配树MAT如何根据支配树发现内存泄漏 运行程序的内存快照导出和分析快照**大文件的处理** 案例实战案例1&#xff1a;…

鼠标录制器哪个好用,5款热门鼠标连点器软件分享(收藏)

鼠标录制怎么操作&#xff1f;在我们日常的工作生活中&#xff0c;经常需要用到屏幕录制工具&#xff0c;如电脑录屏或者手机录屏&#xff0c;使用鼠标录制功能的话&#xff0c;可以省时省力。鼠标录制工具可以记录用户的鼠标移动、点击和键盘输入&#xff0c;并在需要时回放这…

CodeSouler:AI赋能,编程效率的革命性飞跃!

&#x1f525; 功能大揭秘&#xff0c;让你的代码飞起来&#xff01;&#x1f525; 01 添加代码注释 &#x1f4dd; 告别繁琐&#xff0c;一键添加精准注释&#xff01;提升代码清晰度&#xff0c;让后续维护不再是难题。 02 生成单元测试 &#x1f9ea; 智能分析&#xff0c;自…

swiper插件轮播图使用方法(保姆级)

一、swiper下载 swiper官网 可以按自己的需求来下载 一般都是下载最新版本 二、swiper使用方法 1. 解压找到这两个文件&#xff0c;放到vscode对应的文件夹里面&#xff0c;记得在代码中应用这两个文件(我使用的是vscode) 这些轮播图样式都可以自己选择 也可以在官网的在线演…

数模打怪(五)之相关系数

一、什么是相关系数 相关系数&#xff1a;用来衡量两个变量之间的相关性的大小。 根据数据满足的不同条件&#xff0c;选择不同的相关系数进行计算和分析。 两种最为常用的相关系数&#xff1a;person相关系数和spearman等相关系数。 二、Person相关系数 1、什么是Person相…

Linux——进程概念详解

一、进程的基本概念 在给进程下定义之前&#xff0c;我们先了解一下进程&#xff1a; 我们在编写完代码并运行起来时&#xff0c;在我们的磁盘中会形成一个可执行文件&#xff0c;当我们双击这个可执行文件时&#xff08;程序时&#xff09;&#xff0c;这个程序会加载到内存…

【系统架构设计】数据库系统(一)

数据库系统&#xff08;一&#xff09; 数据库模式与范式数据库的结构与模式数据模型关系代数数据的规范化反规范化 数据库设计事务管理备份与恢复分布式数据库系统数据仓库数据挖掘NoSQL大数据 数据库模式与范式 数据库的结构与模式 数据库技术中采用分级的方法将数据库的结…

Linux - 冯-诺依曼体系结构、初始操作系统

目录 冯•诺依曼体系 结构推导 内存提高效率的方法 数据的流动过程 体系结构相关知识 初始操作系统 定位 设计目的 操作系统之上之下分别有什么 管理精髓&#xff1a;先描述&#xff0c;再组织 冯•诺依曼体系 结构推导 计算机基本工作流程图大致如下&#xff1a; 输入设备&a…

vscode 打开远程bug vscode Failed to parse remote port from server output

vscode 打开远程bug vscode Failed to parse remote port from server output 原因如图&#xff1a; 解决&#xff1a;

【数学建模】技术革新——Lingo的使用超详解

目录 基础知识 1. 变量声明 示例 2. 常量声明 语法格式 示例 3. 目标函数 语法格式 示例 4. 约束条件 语法格式 示例 5. 完整的Lingo模型示例 示例 解释 6. 整数变量声明 语法格式 示例 7. 非线性规划 示例 8. 多目标优化 语法格式 示例 9. 数据输入与…

TypeScript 函数类型 (二)

函数类型 函数有两种方式定义 function 关键字来定义函数 function a(){}表达式定义&#xff08;箭头函数的形式&#xff09; const a()>{}函数需要定义类型的有三个地方 入参 和 返回值 以及 函数本身 的类型, 函数本身的类型常用于表达式定义的函数 function sum(a:stri…

洛谷 P1056 [NOIP2008 普及组 T2]:排座椅 ← 贪心算法

【题目来源】https://www.luogu.com.cn/problem/P1056https://www.acwing.com/problem/content/436/【题目描述】 上课的时候总有一些同学和前后左右的人交头接耳&#xff0c;这是令小学班主任十分头疼的一件事情。 不过&#xff0c;班主任小雪发现了一些有趣的现象&#xff0c…

Ubuntu Desktop Docker 配置代理

Ubuntu Desktop Docker 配置代理 主要解决 docker pull 拉取不了镜像问题. Docker Desktop 配置代理 这个比较简单, 直接在 Docker Desktop 里设置 Proxies, 示例如下: http://127.0.0.1:7890 Docker Engine 配置代理 1.Docker Engine 使用下面配置文件即可, root 用户可…

Git的基础操作

环境&#xff1a;Linux操作系统-Centos 创建本地仓库 首先创建一个目录,命名为:gitcode mkdir gitcode进入gitcode目录&#xff0c;创建本地仓库 git init此时&#xff0c;就会创建出了一个空的仓库在当前目录下了&#xff0c;此时目录下就有git的目录了 配置Git 首先重要的…

科技出海|百分点科技智慧政务解决方案亮相非洲展会

近日&#xff0c;华为非洲全联接大会在南非约翰内斯堡举办&#xff0c;吸引政府官员行业专家、思想领袖、生态伙伴等2,000多人参会&#xff0c;百分点科技作为华为云生态合作伙伴&#xff0c;重点展示了智慧政务解决方案&#xff0c;发表《Enable a Smarter Government with Da…