大家好,欢迎来到IT知识分享网。
Linx操作系统中安装java
1、下载jdk
2、在Linux上新建一个目录上传

3、解压文件

4、配置环境变量
vim /etc/profile
在文件的最下面添加:

export JAVA_HOME=/software/jdk1.8.0_421
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
5、执行命令生效
. /etc/profile
6、查看版本
java -version
JDK版本管理工具
网址
https://github.com/FelixSelter/JEnv-for-Windows
安装教程

使用方法
https://github.com/FelixSelter/JEnv-for-Windows
环境变量配置
变量名:JAVA_HOME
变量值:C:\Program Files\Java\jdk1.7.0_51
变量名:Path
变量值:;%JAVA_HOME%\bin;
说明
jdk可以安装在任何位置,不一定安装在C盘。
版本查看方法
命令:java –version
Java命令
javac 类名.java
编译java文件
java 类名
运行class文件
Java -XX:+PrintCommandLineFlags -version
查看默认的垃圾收集器
jar文件
1、JAR(Java Archive,Java 归档文件)是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件。
2、JAR 文件格式以流行的 ZIP 文件格式为基础,与 ZIP 文件不同的是,JAR 文件不仅用于压缩和发布,而且还用于部署和封装库、组件和插件程序,并可被编译器和 JVM 这样的工具直接使用。在 JAR 中包含特殊的文件,如 manifests 和部署描述符,用来指示工具如何处理特定的 JAR文件。
3、使用范围:一个 JAR 文件可以用于
(1) 用于发布和使用类库。
(2)作为应用程序和扩展的构建单元。
(3)作为组件、applet 或者插件程序的部署单位。
(4)用于打包与组件相关联的辅助资源。
jdk1.8采用的编码方式
基本说明
在 Java 1.8 及其早期版本中,JDK 使用了多种编码方式来处理字符数据。主要的编码方案包括:
UTF-16:Java 的内部字符串编码
系统默认编码:用于 I/O 操作的默认字符编码
UTF-16 编码
内部表示
Java 中的 String 和 char 类型使用 UTF-16 编码。这意味着 Java 使用 16 位的 char 类型来表示字符:
基本多语言平面(BMP):绝大多数常用字符(例如 ASCII 字符、汉字等)都在 BMP 中,这些字符用一个 16 位的 char 表示。
辅助平面:一些较少见的字符(例如表情符号和某些历史字符)位于 BMP 之外,这些字符由一对 16 位的 char(称为代理对)表示。
代理对
对于 UTF-16 编码的字符集,某些字符需要两个 16 位的 char(即两个 char 对象),这称为代理对(surrogate pairs)。代理对的范围是从 U+D800 到 U+DFFF。
例如,表情符号 “” 使用一个代理对来表示:
代理对的高位代理(High Surrogate):U+D83D
代理对的低位代理(Low Surrogate):U+DE0A
系统默认编码
文件I/O 和控制台I/O
在文件读写和控制台输入输出等操作中,Java 还涉及到系统默认编码。这种编码在不同操作系统和 Java 环境中可能有所不同。
Windows:通常使用 Cp1252(也称为 Windows-1252)作为默认编码,但有时也可能使用其他编码,例如 Cp936(简体中文)。
Linux 和 macOS:通常使用 UTF-8 编码。
在 Java 1.8 中,你可以通过以下方法获取和设置默认字符编码:

设置编码
你可以在 Java 应用程序启动时,通过 -Dfile.encoding 选项来设置系统的默认编码,例如:

编码转换
在 Java 1.8 中,处理编码转换通常使用 java.nio.charset.Charset 类。你可以使用它来对不同的字符编码进行转换:

总结
1、内部编码:Java 使用 UTF-16 编码来表示 String 和 char。
2、默认编码:在 I/O 操作中,Java 使用系统默认编码,这可能依赖于操作系统和 JVM 设置。
3、编码转换:可以使用 Charset 类进行字符编码和解码的转换。
这些编码机制确保了 Java 程序能够处理各种语言和字符集的文本数据,同时也提供了与其他编码格式兼容的功能。
jdk1.8特性
1、接口的默认方法
Java8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法。(在接口中可以添加扩展方法)
代码示例:

Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。

说明:在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现。
接口的静态方法
基本概念
接口中的静态方法和类中定义的静态方法一样,不属于特定对象,所以它们不是实现接口的api的一部分,必须使用
InterfaceName.staticMethod来调用它们。
特性
1、定义: 静态方法在接口中使用 static 关键字定义,可以在接口上直接调用。
2、访问: 通过接口名来调用静态方法,而不是通过实例或实现类。
3、不继承: 接口的静态方法不会被实现类继承,也不能被实现类重写。
4、用途: 常用于提供与接口相关的实用工具方法或功能。
示例代码

接口的静态方法提供了一种与接口相关的工具,而不是依赖于实现类的实例。
2、Lambda 表达式
基本概念
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使 Java的语言表达能力得到了提升。
Lambda表达式的写法:
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
Runnable runnable = () -> System.out.println(“Lambda表达式”);
我们会发现Lambda表达式的写法更加的简洁、灵活。它只关心参数和执行的功能(具体需要干什么,比如->后的Integer.compare(x, y))。
语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:
(1)左侧:指定了Lambda表达式需要的所有参数。
(2)右侧:指定了Lambda体,即Lambda表达式要执行的功能。
可以是如下的写法:
(params) -> expression
(params) -> statement
(params) -> { statements }
语法格式一:无参,无返回值,Lambda 体只需一条语句
Runnable runnable = () -> System.out.println(“lamda表达式”);
语法格式二:Lambda 只需要一个参数
Consumer<String> consumer=(x)->System.out.println(x);
语法格式三:Lambda 只需要一个参数时,参数的小括号可以省略
Consumer<String> consumer=x->System.out.println(x);
语法格式四:Lambda 需要两个参数
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
BinaryOperator<Integer> binaryOperator=(x,y)->(x+y);
语法格式六:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
BinaryOperator<Integer> bo=(x,y)->{
System.out.println(“Lambda”);
return x+y;};
类型推断
上述 Lambda 表达式中的参数类型都是由编译器推断得出的,Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的,这就是所谓的 “类型推断”。
示例
1、用lambda表达式实现Runnable接口
new Thread( () -> System.out.println(“In Java8, Lambda expression rocks !!”) ).start();
2、循环迭代List
在使用lambda或不使用lambda表达式的情况下迭代列表(List)。你可以看到列表现在有了一个 forEach()方法,它可以迭代所有的对象,并将你的lambda代码应用在其中。
List features = Arrays.asList(“Lambdas”, “Default Method”, “Stream API”, “Date and Time API”);
features.forEach(n -> System.out.println(n));
使用Java 8的方法引用更方便,方法引用由::双冒号操作符标识。
features.forEach(System.out::println);
说明:列表循环的最后一个例子展示了如何在Java 8中使用方法引用(method reference)。
3、函数式接口
基本概念
函数式接口@FunctionalInterface,简称FI,简单的说FI就是指仅含有一个抽象方法的接口,以@Functionalnterface标注,注意这里的抽象方法指的是该接口自己特有的抽象方法,而不包含它从其上级继承过来的抽象方法。
在JDK8中,接口Iterable中默认实现了forEach方法,调用了 JDK8中增加的接口Consumer内的accept方法,执行传入的方法参数。JDK源码如下

Consumer<T>
基本概念
代表了接受一个输入参数并且无返回的操作
源码

作用
处理数据。通过定义一个Consumer对象,我们可以将处理逻辑封装成一个函数,然后在需要使用该处理逻辑的地方直接调用该函数。
方法
void accept(T t);
接受一个参数并执行操作
default Consumer<T> andThen(Consumer<? super T> after)
默认方法,用于将多个 Consumer 组合成一个链式操作
代码示例
要使用Consumer接口,我们需要实现其accept()方法,该方法接受一个参数,表示需要进行处理的数据。例如:

在上述代码中,我们定义了一个名为list的字符串列表,并定义了一个Consumer对象consumer。在consumer.accept()方法中,我们定义了打印参数的逻辑。接着我们调用forEach()方法,并将consumer对象作为参数传入,实现了对列表中所有元素进行处理的目的。
使用场景
1、遍历集合并对每个元素执行操作。
2、日志记录、数据转换等无返回值的操作。
3、回调函数
4、组合多个操作。
遍历集合:

自定义消费逻辑:

实际应用
1、批量处理数据

2、日志记录

3、组合操作

BiConsumer<T, U>
基本概念
BiConsumer<T, U> 是 Consumer 的扩展版本,接受两个参数。
Function<T,R>
基本概念
它定义了一个具有一个输入参数和一个输出参数的函数,我们可以使用Function接口来定义一些简单的转换操作。
源码

方法
R apply(T t)
参数:
t:函数的参数
R:函数的结果
将函数应用于给定的参数
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after)
返回一个组合函数,首先应用当前函数,然后应用指定的后续函数。
compose(Function<? super V, ? extends T> before)
返回一个组合函数,首先应用指定的前置函数,然后应用当前函数。
代码示例
1、将一个字符串转换为其长度

2、组合函数

3、使用compose 方法

适用场景
1、数据转换
2、流处理中的映射操作
3、作为方法参数传递的回调函数
总结
Function<T, R> 接口提供了一种灵活的方法来处理输入和输出之间的转换,可以有效地与 Java 8 的流和其他函数式编程特性结合使用,提升代码的可读性和可维护性。
BiFunction
基本概念
BiFunction 是 Java 中的一个函数式接口,它定义了一个接收两个参数并返回结果的函数。具体来说,BiFunction 接口有以下方法签名:
R apply(T t, U u)
其中,T 和 U 是输入参数的类型,R 是返回结果的类型。apply 方法接收一个类型为 T 的参数和一个类型为 U 的参数,并返回一个类型为 R 的结果。
源码

方法
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after)
返回一个新的函数,该函数首先对输入应用 BiFunction,然后对结果应用指定的函数。
作用
允许开发者自定义逻辑来处理两个输入参数,并产生一个结果。它可以用于各种场景,例如数据转换、聚合操作、复杂计算等。
数据转换
BiFunction 可以将两个输入参数转换为一个输出结果。例如,将两个整数相加得到它们的和:

聚合操作
BiFunction 可以用于聚合操作,将多个值合并为一个值。例如,将两个字符串拼接在一起:

复杂计算
BiFunction 可用于处理复杂的计算逻辑,根据输入参数生成一个结果。例如,计算两个数字的乘积:

Supplier<T>
基本概念
无参数,返回一个结果。用于表示一个供应者。它没有任何参数,但可以提供一个类型为 T 的返回值。Supplier<T> 接口只定义了一个抽象方法 T get(),该方法用于获取一个值。
源码

作用
在于延迟生成或提供一个值,通过调用 get() 方法来获取这个值。
使用场景
惰性求值
在某些情况下,我们希望推迟计算或生成某个值,直到真正需要它的时候再进行计算。使用 Supplier<T> 可以将值的生成逻辑延迟到需要的时候才执行。
依赖注入
在某些情况下,我们希望将值的获取逻辑从调用方解耦出来,使用 Supplier<T> 可以将值的提供者抽象化,由外部传入。
延迟初始化
当我们需要在对象创建或初始化时,动态地提供某个值,而不是在一开始就立即确定该值。使用 Supplier<T> 可以在需要的时候获取该值。
方法
T get();
代码示例

Predicate
基本概念
用于表示一个断言,即接受一个参数并返回一个布尔值。Predicate<T> 接口定义了一个抽象方法 boolean test(T t),该方法用于对给定的输入值进行判断,并返回一个布尔结果。
源码

方法
boolean test(T t);
接受一个参数并返回一个布尔值。
default Predicate<T> and(Predicate<? super T> other)
返回一个新的 Predicate,表示当前 Predicate 和 other 的逻辑与(AND)
default Predicate<T> negate()
default Predicate<T> or(Predicate<? super T> other)
static <T> Predicate<T> isEqual(Object targetRef)
返回一个 Predicate,用于判断输入对象是否与 target 相等
代码示例

使用场景
1、过滤集合
Predicate 常用于结合 Stream API 对集合进行过滤。

2、条件判断
Predicate 可以用于封装复杂的条件判断逻辑。

3、动态条件组合
通过组合多个 Predicate,可以动态构建复杂的条件逻辑。

注意事项
1、空值处理
如果输入参数可能为 null,需要在 test 方法中显式处理,避免 NullPointerException。
2、性能
对于复杂的条件判断,Predicate 的性能与传统的 if-else 语句相当,但代码更简洁。
3、组合逻辑
使用 and、or 和 negate 方法时,注意逻辑运算的优先级和顺序。
Comparator<T>
基本概念
Comparator<T> 接口是用于定义对象的比较规则的接口。它允许我们根据自定义的排序逻辑对对象进行比较和排序。
方法
int compare(T o1, T o2)
用于比较两个对象 o1 和 o2 的顺序。该方法返回一个负整数、零或正整数,具体的返回值意义如下:
返回负整数:表示 o1 小于 o2,即 o1 应该排在 o2 之前。
返回零:表示 o1 等于 o2,它们的顺序不变。
返回正整数:表示 o1 大于 o2,即 o1 应该排在 o2 之后。
通过实现 Comparator<T> 接口,我们可以根据自己的需求来定义对象的比较规则。这使得我们可以按照任意的方式对对象进行排序,而不仅限于对象自身的默认排序规则(比如实现 Comparable<T> 接口)。
示例



上面的例子中,我们定义了一个 Student 类,包含姓名和年龄两个属性。然后,我们实现了一个 Comparator<Student> 接口的实现类 StudentAgeComparator,通过比较学生的年龄来定义排序规则。最后,在主函数中,我们创建了一个学生列表,使用 Collections.sort() 方法和自定义的比较器对学生列表按照年龄进行排序,然后打印排序结果。通过自定义比较器,我们可以根据不同的需求来对对象进行排序,而不需要修改对象本身的类或实现标准的自然排序接口。
除了在集合中排序,Comparator<T> 接口还可以在其他需要比较对象的地方使用,比如搜索算法、优先队列等。
4、方法与构造函数引用
基本概念
方法引用是一种简化Lambda表达式的方式,它可以直接引用已有的Java方法或构造函数,从而避免重复编写Lambda表达式。方法引用可以使代码更加简洁、易于理解。
分类
1、静态方法引用
可以引用一个类中的静态方法,例如:
ClassName::staticMethodName
2、实例方法引用
可以引用一个特定对象中的实例方法,例如:
object::instanceMethodName
3、构造函数引用
可以引用一个类的构造函数,例如:ClassName::new
4、超类方法引用
可以引用超类中定义的方法,例如:super::methodName
使用场景
方法引用可以用于任何函数式接口,只需要满足参数类型、返回值类型和函数式接口中抽象方法的参数类型、返回值类型相同即可。使用方法引用可以使代码更加简洁、易于理解,特别是对于重复的Lambda表达式而言,方法引用可以避免代码的重复。
代码示例

在上述代码中,我们使用了方法引用语法System.out::println,避免了编写Lambda表达式。该语法指定了调用System.out的println方法,并将其作为参数传递给forEach()方法,从而实现了对列表中所有元素进行输出的目的。
注意事项
1、方法引用只能用于函数式接口,接口中必须只有一个抽象方法。
2、使用方法引用可以使代码更加简洁、易于理解,特别是对于重复的Lambda表达式而言,方法引用可以避免代码的重复。
3、方法引用还可以和Lambda表达式一起使用,对于需要进行多次转换的场景更加方便。
5、Lambda作用域
基本概念
你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。Lambda表达式不会从超类(supertype)中继承任何变量名,也不会引入一个新的作用域。Lambda表达式基于词法作用域,也就是说lambda表达式函数体里面的变量和它外部环境的变量具有相同的语义(也包括lambda表达式的形式参数)。此外this关键字及其引用,在Lambda表达式内部和外部也拥有相同的语义。
6、访问局部变量
(1)可以直接在lambda表达式中访问外层的局部变量
例如:

但是和匿名对象不同的是,lambda表达式的局部变量(eg:num)可以不用声明为final。

不过这里的局部变量(eg:num)必须不可被后面的代码修改(即隐性的具有final的语义),下面的代码无法编译:

在Lambda表达式中试图修改局部变量是不允许的。
(2)在 Lambda 表达式当中被引用的变量的值不可以被更改。

(3)在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

7、访问对象字段与静态变量
8、访问接口的默认方法
代码示例:

在上面的示例中,MyInterface接口包含一个默认方法defaultMethod和一个抽象方法regularMethod。MyClass类实现了MyInterface接口,并提供了对regularMethod方法的实现。在Main类的main方法中,我们创建了MyClass的实例,并通过该实例调用了默认方法和抽象方法的实现。
运行代码输出以下内容:

这样就成功地访问了接口的默认方法。
9、Date API
Java 8 在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多,但又不完全一样。
(1)Clock时钟
Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。
代码示例:
Clock clock = Clock.systemDefaultZone();
long mill = clock.millis();
System.out.println(mill);
Instant instant = clock.instant();
Date date = Date.from(instant);
System.out.println(date);
(2)Timezones 时区
在新API中时区使用ZoneId来表示。时区可以很方便的使用静态方法of来获取到。时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。
代码示例:
(3)LocalTime本地时间
LocalTime 定义了一个没有时区信息的时间,例如晚上10点或者 17:30:15。下面的例子使用前面代码创建的时区创建了两个本地时间。
(4)LocalDate 本地日期
10、Annotation注解
jdk17特性
基本概念
JDK 17 在 2021 年 9 月 14 号正式发布了!根据发布的规划,这次发布的 JDK 17 是一个长期维护的版本(LTS)。Java 17 提供了数千个性能、稳定性和安全性更新,以及 14 个 JEP(JDK 增强提案),进一步改进了 Java 语言和平台,以帮助开发人员提高工作效率。JDK 17 包括新的语言增强、库更新、对新 Apple (Mx CPU)计算机的支持、旧功能的删除和弃用,并努力确保今天编写的 Java 代码在未来的 JDK 版本中继续工作而不会发生变化。
密封的类和接口(正式版)
基本概念
封闭类可以是封闭类和或者封闭接口,用来增强 Java 编程语言,防止其他类或接口扩展或实现它们。这个特性由Java 15的预览版本晋升为正式版本。因为我们引入了sealed class或interfaces,这些class或者interfaces只允许被指定的类或者interface进行扩展和实现。使用修饰符sealed,您可以将一个类声明为密封类。密封的类使用reserved关键字permits列出可以直接扩展它的类。子类可以是最终的,非密封的或密封的。
之前我们的代码是这样的。

但是我们现在要限制 Person类 只能被这三个类继承,不能被其他类继承,需要这么做。

很强很实用的一个特性,可以限制类的层次结构。
JEP 306:恢复始终严格的浮点语义
Java 编程语言和 Java 虚拟机最初只有严格的浮点语义。从 Java 1.2 开始,默认情况下允许在这些严格语义中进行微小的变化,以适应当时硬件架构的限制。这些差异不再有帮助或必要,因此已被 JEP 306 删除。
https://pdai.tech/md/java/java8up/java17.html
文本块
基本概念
Java 17 引入了一项新的语言特性,即文本块(Text Blocks),也称为多行字符串。文本块允许在代码中更方便地编写多行字符串,而无需使用传统的转义序列或字符串连接操作符。
文本块在编写包含大段文本或格式化字符串的代码时非常有用,例如 SQL 查询、HTML 片段、JSON 数据等。它简化了代码的编写,并提高了可读性和维护性。
文本块由三个双引号(”””)开始和结束,并且可以包含多行文本。下面是一个简单的示例:

在上面的示例中,textBlock 变量包含了一个文本块,其中包含了三行文本。文本块中的缩进和换行符都会被保留,因此文本块的输出结果将保持与代码中定义的格式一致。
特点
1、缩进控制:文本块中的每行文本会保留与代码中相同的缩进级别。这样可以使多行文本保持良好的可读性,并且不需要额外的空格或制表符。
2、转义字符:文本块中的转义字符(如 \n、\t 等)不会被解析,而会被直接当作普通字符处理。这样可以避免在字符串中使用大量的转义序列。
3、行尾空白:文本块中每行的行尾空白(包括空格和制表符)会被保留,除非在行的结尾显式使用了 \ 进行行续行。
4、引号处理:文本块中的双引号不需要进行转义,因为文本块是由三个双引号进行界定的。
怎么转义双引号
在 Java 17 的文本块中,如果你需要在文本块中包含双引号,你可以使用双引号进行转义。具体来说,你可以使用两个双引号(””)来表示一个双引号字符。
instanceof操作符的模式匹配
switch表达式
基本概念
switch表达式与switch语句有所不同。switch语句只能作为语句使用,只能对数据进行求值,而不能返回值。而switch表达式作为表达式使用,可以返回值,并且可以在case中使用模式匹配。
示例代码
下面是一个使用if/else if和instanceof的示例代码

上述代码可以使用switch表达式进行改写

switch表达式与switch语句在使用上有一些区别。首先是在case后面使用的操作符,表达式中使用箭头(->),而语句中仍然使用冒号(:)。例如:

需要注意的是,使用switch语句时仍然需要使用break语句来终止switch流程,否则将继续执行下一个代码块。
Record
基本概念
Record是一种特殊的类,专门用来存储不可变数据,自动生成常用方法。
传统写法vs Record
传统写法

Record写法

Record自动提供什么
1、构造方法
2、getter方法(方法名就是字段名)
3、equals()、hashCode()、toString()方法
4、所有字段都是final的
使用示例

限制
1、Record是final的,不能被继承
2、不能声明实例字段(除了Record组件)
3、所有字段都是不可变的
总结
Record就是专门用来装数据的”盒子”,Java帮你自动生成所有基础方法。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/185728.html