Java语言入门到精通章节
- 学习笔记:Java-基础篇(第一部分)_ljtxy.love的博客-CSDN博客
- 学习笔记:Java-中级篇(第二部分)_ljtxy.love的博客-CSDN博客
- 学习笔记:Java-高级篇(第三部分)_ljtxy.love的博客-CSDN博客
- 学习笔记:Java-进阶篇(一)(第四部分)_ljtxy.love的博客-CSDN博客
- 学习笔记:Java-进阶篇(二)(第五部分)_ljtxy.love的博客-CSDN博客
- 学习笔记:Java8新特性_ljtxy.love的博客-CSDN博客
文章目录
1.概述
笔记小结:
- 概述:JDK1.8所出现的新特性
- 新特性:
- Lambda 表达式
- 方法引用
- 默认方法
- Stream API
- Date Time API
- Optional 类
- ……
1.1含义
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
1.2新特性
- 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应用。
说明:
- Java8 新增了非常多的特性,我们主要讨论以上几个
- 更多特性,参考:What’s New in JDK 8 (oracle.com)
2.Lambda 表达式
笔记小结:
概述:使代码变的更加简洁紧凑
语法:
实现的这个接口中的抽象方法中的形参列表 -> 抽象方法的处理 // 例如 (parameters) -> expression 或 (parameters) ->{ statements; }
变量作用域:
- 在Lambda表达式中试图修改被Final关键字修饰的局部变量是不允许的
- 在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量
2.1概述
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。
2.2语法
JDK1.8之后引入的一种语法,他的写法是使用一个->
符号,箭头将Lambda表达式分为左右两部分,左边写的是实现的这个接口中的抽象方法中的形参列表,右边就是对抽象方法的处理;
实现的这个接口中的抽象方法中的形参列表 -> 抽象方法的处理
// 例如
(parameters) -> expression
或
(parameters) ->{
statements; }
说明:
- **可选类型声明:**不需要声明参数类型,编译器可以统一识别参数值
- **可选的参数圆括号:**一个参数无需定义圆括号,但多个参数需要定义圆括号
- **可选的大括号:**如果主体包含了一个语句,就不需要使用大括号
- **可选的返回关键字:**如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值
2.3基本用例
// 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)
参考链接:详解Java中的Lambda表达式_java lambda表达式_明天,你好呀的博客-CSDN博客
public class Java8Tester {
public static void main(String args[]){
Java8Tester tester = new Java8Tester();
// 类型声明 -----注意,此处是重写了接口,并用Lambda表达式进行简化后的写法
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");
}
@FunctionalInterface // 函数式接口注解(只包含一个抽象方法的接口,称为函数式接口)
interface MathOperation {
int operation(int a, int b);
}
@FunctionalInterface
interface GreetingService {
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}
注意:
- Lambda 表达式主要用来定义行内执行的函数式接口
- Lambda 表达式免去了使用匿名方法的麻烦,并且给予 Java 简单但是强大的函数化的编程能力
2.4变量作用域
2.4.1成员变量
含义:在Lambda表达式中试图修改局部变量是不允许的
public class Java8Tester {
final static String salutation = "Hello! ";
// static String salutation = "Hello! "; 可以修改
// static String salutation = "Hello! "; 可以修改
public static void main(String args[]){
GreetingService greetService1 = message -> System.out.println(salutation + message);
// GreetingService greetService1 = message -> System.out.println(salutation ="Test");
greetService1.sayMessage("Runoob");
}
interface GreetingService {
void sayMessage(String message);
}
}
说明:
- 可以在lambda表达式中访问外层的局部变量
- 不能在lambda表达式中修改外层的被Final修饰的局部变量
2.4.2局部变量参数
含义:在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量
String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());
说明:
编译会出错 ,first已重复定义
3.方法引用
笔记小结:已学,详细参考本套 笔记,Java进阶篇
4.函数式接口
笔记小结:
概述:函数式接口可以被隐式转换为 lambda 表达式,以简化代码,提高代码的可读性和可维护性。
函数式接口:
Consumer接口(消费接口)
Consumer<String> consumer = s -> System.out.println(s); consumer.accept("Hello world");
说明:接受一个输入参数,没有返回值
Supplier接口(生产接口)
Supplier<String> supplier = () -> "Hello world"; String str = supplier.get(); System.out.println(str);
说明:接受一个输入参数,返回一个结果
Function接口(函数式接口)
Function<String, Integer> function = s -> s.length(); int length = function.apply("Hello world"); System.out.println(length);
说明:接受一个输入参数,返回一个结果
Predicate接口(断言式接口)
Predicate<String> predicate = s -> s.length() > 5; boolean result = predicate.test("Hello world"); System.out.println(result);
说明:接受一个输入参数,返回一个布尔值
4.1概述
4.1.1含义
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
4.1.2定义
将@Functionallnterface放在接口之上,如果接口是函数式接口,编译通过;如果不是,编译失败
示例:
@FunctionalInterface
interface GreetingService {
void sayMessage(String message);
}
// 实现
GreetingService greetService1 = message -> System.out.println("Hello " + message);
说明:
Lambda表达式的书写方式,需要函数式接口才能进行简写
4.2常用函数式接口
4.2.1Consumer接口
4.2.1.1概述
Consumer< T >接口也被称为消费型接口,它消费的数据类型由泛型指定
4.2.1.2常用方法
Consumer< T >:包含两个方法。
- void accept(T t):对给定的参数执行此操作
- default Consumer < T > andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
4.2.1.3基本用例
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
// 例如
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("Hello world");
说明:
接受一个输入参数,没有返回值
4.2.1.4底层源码
4.2.2Supplier接口
4.2.2.1概述
Supplier< T >接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会产生什么类型的数据供我们使用
4.2.2.2常用方法
- T get():获得结果
4.2.2.3基本用例
@FunctionalInterface
public interface Supplier<T> {
T get();
}
// 例如
Supplier<String> supplier = () -> "Hello world";
String str = supplier.get();
System.out.println(str);
说明:
提供一个输出参数,没有输入参数
4.2.2.4底层源码
4.2.3Function接口
4.2.3.1概述
Function<T,R>:接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新值
4.2.3.2常用方法
- R apply(T t):将此函数应用于给定的参数
- default< V >:Function andThen(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
4.2.3.3基本用例
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
// 例如
Function<String, Integer> function = s -> s.length();
int length = function.apply("Hello world");
System.out.println(length);
说明:
接受一个输入参数,返回一个结果
4.2.3.4底层源码
4.2.4Predicate接口
4.2.4.1概述
Predicate< T >:接口通常用于判断参数是否满足指定的条件
4.2.4.2常用方法
- boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
- default Predicate< T > negate():返回一个逻辑的否定,对应逻辑非
- default Predicate< T > and():返回一个组合判断,对应短路与
- default Predicate< T > or():返回一个组合判断,对应短路或
- isEqual():测试两个参数是否相等
4.2.4.3基本用例
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
// 例如
Predicate<String> predicate = s -> s.length() > 5;
boolean result = predicate.test("Hello world");
System.out.println(result);
说明:
接受一个输入参数,返回一个布尔值
4.2.4.4底层原理
5.默认方法
笔记小结:
概述:默认方法就是接口可以有实现方法,而且不需要实现类去强制实现其方法
语法:
public interface Vehicle { default void print(){ System.out.println("我是一辆车!"); } }
多个默认方法:若实现多个接口,且接口的方法同名,那么可重写此方法或者通过Super关键字进行指定接口调用
public class Car implements Vehicle, FourWheeler { public void print(){ Vehicle.super.print(); } }
静态默认方法:静态默认方法,可以直接调用,并且不会强制重写此方法
public interface Vehicle { // 静态方法 static void blowHorn(){ System.out.println("按喇叭!!!"); } }
5.1概述
5.1.1含义
Java 8 新增了接口的默认方法。简单说,默认方法就是接口可以有实现方法,而且不需要实现类去强制实现其方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。
5.1.2作用
进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题
5.2语法
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
}
说明:
在接口中加入default关键字
5.3多个默认方法
当一个类实现了多个接口,并且接口中的方法同名时,可以重写接口方法,或者通过super关键字进行指定调用
// 接口
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
}
public interface FourWheeler {
default void print(){
System.out.println("我是一辆四轮车!");
}
}
// 重写接口默认方法
public class Car implements Vehicle, FourWheeler {
default void print(){
System.out.println("我是一辆四轮汽车!");
}
}
// 通过super调用指定接口的默认方法
public class Car implements Vehicle, FourWheeler {
public void print(){
Vehicle.super.print();
}
}
5.4静态默认方法
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
// 静态方法
static void blowHorn(){
System.out.println("按喇叭!!!");
}
}
说明:
接口中的静态方法,可以直接调用
示例:
Vehicle.blowHorn();
6.Stream流
笔记小结:已学,详细参考本套笔记,Java进阶篇
7.Optional 类
笔记小结:
- 概述:
- 含义:Optional 类是一个可以为null的容器对象
- 作用:可以很好的解决空指针异常
- 常用成员方法:
- 获取Optional对象:
- ofNullable:如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional
- of:返回一个指定非null值的Optional
- 判断值存在:
- isPresent :如果值存在则方法会返回true,否则返回 false。
- isEmpty:如果值不存在则方法会返回true,否则返回 false。
- orElse :如果存在该值,返回值, 否则返回 other
- 获取值:
- get:如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
7.1概述
7.1.1含义
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。ptional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
7.1.2作用
Optional 类的引入很好的解决空指针异常
7.2常用成员方法
序号 | 方法 & 描述 |
---|---|
1 | **static Optional empty()**返回空的 Optional 实例。 |
2 | **boolean equals(Object obj)**判断其他对象是否等于 Optional。 |
3 | **Optional filter(Predicate<? super predicate)**如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。 |
4 | ** Optional flatMap(Function<? super T,Optional> mapper)**如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional |
5 | **T get()**如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException |
6 | **int hashCode()**返回存在值的哈希码,如果值不存在 返回 0。 |
7 | **void ifPresent(Consumer<? super T> consumer)**如果值存在则使用该值调用 consumer , 否则不做任何事情。 |
8 | **boolean isPresent()**如果值存在则方法会返回true,否则返回 false。 |
9 | **Optional map(Function<? super T,? extends U> mapper)**如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。 |
10 | **static Optional of(T value)**返回一个指定非null值的Optional。 |
11 | **static Optional ofNullable(T value)**如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。 |
12 | **T orElse(T other)**如果存在该值,返回值, 否则返回 other。 |
13 | **T orElseGet(Supplier<? extends T> other)**如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。 |
14 | ** T orElseThrow(Supplier<? extends X> exceptionSupplier)**如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常 |
15 | **String toString()**返回一个Optional的非空字符串,用来调试 |
7.3基本用例
import java.util.Optional;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
8.Nashorn JavaScript
笔记小结:Nashorn JavaScript Engine 在 Java 15 已经不可用了,因此详细参考:Java 8 Nashorn JavaScript | 菜鸟教程 (runoob.com)
9.日期时间 API
笔记小结:已学,详细参考本套笔记,Java高级篇
10.Base64编码
笔记小结:
- 概述:Base64是一种用于将二进制数据编码为ASCII字符的编码方式
- 分类:
- 基本:
- Encoder
- Decoder
- URL:
- getUrlEncoder
- getUrlDecoder
- MIME
- getMimeEncoder
- getMimeDecoder
10.1概述
10.1.1含义
在Java 8中,Base64编码已经成为Java类库的标准。Java8中提供了Base64类来支持Base64编码和解码
10.1.2作用
Base64是一种用于将二进制数据编码为ASCII字符的编码方式,常用于在网络传输时将二进制数据转换为可读的字符串
10.1.3分类
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
- **基本:**输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/
- **URL:**输出映射到一组字符A-Za-z0-9+_,输出是URL和文件
- **MIME:**输出隐射到MIME友好格式。输出每行不超过76字符,并且使用’\r’并跟随’\n’作为分割。编码输出最后没有行分割
10.2内嵌类
序号 | 内嵌类 & 描述 |
---|---|
1 | static class Base64.Decoder该类实现一个解码器用于,使用 Base64 编码来解码字节数据。 |
2 | static class Base64.Encoder该类实现一个编码器,使用 Base64 编码来编码字节数据。 |
10.3常用成员方法
序号 | 方法名 & 描述 |
---|---|
1 | **static Base64.Decoder getDecoder()**返回一个 Base64.Decoder ,解码使用基本型 base64 编码方案。 |
2 | **static Base64.Encoder getEncoder()**返回一个 Base64.Encoder ,编码使用基本型 base64 编码方案。 |
3 | **static Base64.Decoder getMimeDecoder()**返回一个 Base64.Decoder ,解码使用 MIME 型 base64 编码方案。 |
4 | **static Base64.Encoder getMimeEncoder()**返回一个 Base64.Encoder ,编码使用 MIME 型 base64 编码方案。 |
5 | **static Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator)**返回一个 Base64.Encoder ,编码使用 MIME 型 base64 编码方案,可以通过参数指定每行的长度及行的分隔符。 |
6 | **static Base64.Decoder getUrlDecoder()**返回一个 Base64.Decoder ,解码使用 URL 和文件名安全型 base64 编码方案。 |
7 | **static Base64.Encoder getUrlEncoder()**返回一个 Base64.Encoder ,编码使用 URL 和文件名安全型 base64 编码方案。 |
10.4基本用例
public class Java8Tester {
public static void main(String args[]){
try {
// 基本编码
String base64encodedString = Base64.getEncoder().encodeToString("runoobjava8".getBytes("utf-8"));
System.out.println("Base64 编码字符串 (基本) :" + base64encodedString);
// 基本解码
byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
// URL 和文件名安全型 编码
System.out.println("原始字符串: " + new String(base64decodedBytes, "utf-8"));
base64encodedString = Base64.getUrlEncoder().encodeToString("runoob?java8".getBytes("utf-8"));
System.out.println("Base64 编码字符串 (URL) :" + base64encodedString);
// MIME 型 编码
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 10; ++i) {
stringBuilder.append(UUID.randomUUID().toString());
}
byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
System.out.println("Base64 编码字符串 (MIME) :" + mimeEncodedString);
}catch(UnsupportedEncodingException e){
System.out.println("Error :" + e.getMessage());
}
}
}