java8新特性-掌握

Lambda表达式
* 2.格式:
-> :lambda操作符 或 箭头操作符
->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)
->右边:lambda体 (其实就是重写的抽象方法的方法体)
* 3. Lambda表达式的使用:(分为6种情况介绍)总结:
->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字
* 4.Lambda表达式的本质:作为函数式接口的实例
* 5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口(接口的方法都是隐式抽象)。我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。
* 6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
六种情况
// 语法格式一:无参,无返回值
@Test
public void test1(){
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("1111111111");
}
};
Runnable runnable2 = ()->{
System.out.println("2222222222222222222");
};
runnable1.run();
runnable2.run();
}
// 语法格式二:Lambda 需要一个参数,但是没有返回值。
// 语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
// 语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
// 语法格式五:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
@Test
public void test2(){
Consumer<String> consumer1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer2 = (String s)->{
System.out.println(s);
};
Consumer<String> consumer3 = (s)->{
System.out.println(s);
};
Consumer<String> consumer4 = s->{
System.out.println(s);
};
Consumer<String> consumer5 = s-> System.out.println(s);
consumer1.accept("11111");
consumer2.accept("2222");
consumer3.accept("3333");
consumer4.accept("4444");
consumer5.accept("5555");
}
// 语法格式六:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test
public void test6(){
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
Comparator<Integer> comparator2 = (o1,o2)->{
return o1.compareTo(o2);
};
System.out.println(comparator1.compare(10,20));
System.out.println(comparator2.compare(21,20));
}
函数式(Functional)接口

方法引用与构造器引用
方法引用
* 1.使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
* 2.方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以
* 方法引用,也是函数式接口的实例。
*
* 3. 使用格式: 类(或对象) :: 方法名
*
* 4. 具体分为如下的三种情况:
* 情况1 对象 :: 非静态方法
* 情况2 类 :: 静态方法
*
* 情况3 类 :: 非静态方法
*
* 5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的
* 形参列表和返回值类型相同!(针对于情况1和情况2)
// 情况一:对象 :: 实例方法
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
@Test
public 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("beijing");
}
// 情况二:类 :: 静态方法
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
@Test
public void test3() {
Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12,21));
System.out.println("*******************");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(12,3));
}
// 情况三:类 :: 实例方法 (有难度)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
@Test
public 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("abd","abm"));
}
构造器引用
* 一、构造器引用
* 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
* 抽象方法的返回值类型即为构造器所属的类的类型
*
* 二、数组引用
* 大家可以把数组看做是一个特殊的类,则写法与构造器引用一致。
//构造器引用
//Supplier中的T get()
//Employee的空参构造器:Employee()
@Test
public void test1(){
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
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());
}
//BiFunction中的R apply(T t,U u)
@Test
public void test3(){
BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);
System.out.println(func1.apply(1001,"Tom"));
System.out.println("*******************");
BiFunction<Integer,String,Employee> func2 = Employee :: new;
System.out.println(func2.apply(1002,"Tom"));
}
//数组引用
//Function中的R apply(T t)
@Test
public void test4(){
Function<Integer,String[]> func1 = length -> new String[length];
String[] arr1 = func1.apply(5);
System.out.println(Arrays.toString(arr1));
System.out.println("*******************");
Function<Integer,String[]> func2 = String[] :: new;
String[] arr2 = func2.apply(10);
System.out.println(Arrays.toString(arr2));
}
强大的Stream API
概念
* 1. Stream关注的是对数据的运算,与CPU打交道
* 集合关注的是数据的存储,与内存打交道
*
* 2.
* ①Stream 自己不会存储元素。
* ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
* ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
*
* 3.Stream 执行流程
* ① Stream的实例化
* ② 一系列的中间操作(过滤、映射、...)
* ③ 终止操作
*
* 4.说明:
* 4.1 一个中间操作链,对数据源的数据进行处理
* 4.2 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
创建Stream
// 创建 Stream方式一:通过集合
@Test
public void test1(){
List<User> users = UserData.getUsers();
// 顺序流
Stream<User> stream = users.stream();
// 并行流
Stream<User> parallelStream = users.parallelStream();
System.out.println(stream);
System.out.println(parallelStream);
}
//创建 Stream方式二:通过数组
@Test
public void test2(){
int[] arr = new int[]{1,2,34,6};
IntStream stream = Arrays.stream(arr);
User[] users = new User[]{new User("aa",10),new User("bb",20)};
Stream<User> stream1 = Arrays.stream(users);
System.out.println(stream);
System.out.println(stream1);
}
//创建 Stream方式三:通过Stream的of()
@Test
public void test3(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
System.out.println(integerStream);
}
//创建 Stream方式四:创建无限流
@Test
public void test4() {
// public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历前10个偶数
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
// public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
中间操作
筛选与切片
// 筛选与切片
@Test
public void test1(){
List<User> users = UserData.getUsers();
// filter(Predicate p) 接收 Lambda , 从流中排除某些元素
users.stream().filter(item -> item.getAge() > 50).forEach(System.out::println);
System.out.println();
// distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
users.stream().distinct().forEach(System.out::println);
System.out.println();
// limit(long maxSize) 截断流,使其元素不超过给定数量
users.stream().limit(3).forEach(System.out::println);
System.out.println();
// skip(long n) 跳过元素,返回一个扔掉了前n个空流,若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
users.stream().skip(3).limit(5).forEach(System.out::println);
}
映射
// 映射
@Test
public void test2(){
List<User> users = UserData.getUsers();
// map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
users.stream().map(item->item.getName()).forEach(System.out::println);
System.out.println();
// flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
users.stream().map(item->item.getName()).flatMap(item -> StreamAPITest1.fromStringToStream(item)).forEach(System.out::println);
}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str){//aa
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
排序
// 排序
@Test
public void test4(){
List<User> users = UserData.getUsers();
// sorted()——自然排序
users.stream().sorted().forEach(System.out::println);
System.out.println();
// sorted(Comparator com)——定制排序
users.stream().sorted(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
int compare = Integer.compare(o2.getAge(), o1.getAge());
if (compare != 0 ) {
return compare;
}else {
return o2.getName().compareTo(o1.getName());
}
}
}).forEach(System.out::println);
}
终止操作
匹配与查找
// 匹配与查找
@Test
public void test1(){
List<User> users = UserData.getUsers();
// allMatch(Predicate p) 检查是否匹配所有元素
boolean b = users.stream().allMatch(item -> item.getAge() > 9);
System.out.println(b);
System.out.println();
// anyMatch(Predicate p) 检查是否至少匹配一个元素
boolean b1 = users.stream().anyMatch(item -> item.getAge() > 70);
System.out.println(b1);
System.out.println();
// noneMatch(Predicate p) 检查是否没有匹配所有元素
boolean b2 = users.stream().noneMatch(item -> item.getAge() > 90);
System.out.println(b2);
System.out.println();
// findFirst() 返回第一个元素
Optional<User> first = users.stream().findFirst();
System.out.println(first);
System.out.println();
// findAny() 返回当前流中的任意元素
Optional<User> any = users.stream().findAny();
System.out.println(any);
System.out.println();
// count() 返回流中元素总数
long count = users.stream().count();
System.out.println(count);
System.out.println();
// max(Comparator c) 返回流中最大值
Optional<User> max = users.stream().max((o1,o2)->{
return Integer.compare(o1.getAge(),o2.getAge());
});
System.out.println(max);
System.out.println();
// min(Comparator c) 返回流中最小值
Optional<User> min = users.stream().min((o1,o2)->{
return Integer.compare(o1.getAge(),o2.getAge());
});
System.out.println(min);
System.out.println();
// forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代——它帮你把迭代做了)
users.stream().forEach(System.out::println);
}
归约
// 归约
@Test
public void test3(){
List<User> users = UserData.getUsers();
// Integer reduce = users.stream().map(item -> item.getAge()).reduce(0, Integer::sum);
// System.out.println(reduce);
// System.out.println();
Optional<Integer> reduce = users.stream().map(item -> item.getAge()).reduce((i1, i2) -> {
return i1 + i2;
});
System.out.println(reduce.get());
System.out.println();
}
收集
// 收集
@Test
public void test4(){
List<User> users = UserData.getUsers();
List<Integer> collect = users.stream().map(item -> item.getAge()).collect(Collectors.toList());
System.out.println(collect);
Set<Integer> collect1 = users.stream().map(item -> item.getAge()).collect(Collectors.toSet());
System.out.println(collect1);
// users.stream().collect(Collectors.toMap(key,val));
}

Optional类
概念
为了在程序中避免出现空指针异常而创建的。
* 创建Optional类对象的方法:
Optional.of(T t) : 创建一个 Optional 实例, t必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t): t可以为null
* 判断Optional容器中是否包含对象:
boolean isPresent() : 判断是否包含对象
void ifPresent(Consumer<? super T> consumer) : 如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
* 获取Optional容器的对象:
T get(): 如果调用对象包含值,返回该值,否则抛异常
T orElse(T other) : 如果有值则将其返回,否则返回指定的other对象。
T orElseGet(Supplier<? extends T> other) : 如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
T orElseThrow(Supplier<? extends X> exceptionSupplier) : 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
public class Boy {
private Girl girl;
@Override
public String toString() {
return "Boy{" +
"girl=" + girl +
'}';
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
public Boy() {
}
public Boy(Girl girl) {
this.girl = girl;
}
}
public class Girl {
private String name;
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Girl() {
}
public Girl(String name) {
this.name = name;
}
}
public class OptionalTest {
/*
Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):t可以为null
*/
@Test
public void test1(){
Girl girl = new Girl();
// girl = null;
//of(T t):保证t是非空的
Optional<Girl> optionalGirl = Optional.of(girl);
}
@Test
public void test2(){
Girl girl = new Girl();
// girl = null;
//ofNullable(T t):t可以为null
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println(optionalGirl);
//orElse(T t1):如果单前的Optional内部封装的t是非空的,则返回内部的t.
//如果内部的t是空的,则返回orElse()方法中的参数t1.
Girl girl1 = optionalGirl.orElse(new Girl("赵丽颖"));
System.out.println(girl1);
}
public String getGirlName(Boy boy){
return boy.getGirl().getName();
}
@Test
public void test3(){
Boy boy = new Boy();
boy = null;
String girlName = getGirlName(boy);
System.out.println(girlName);
}
//优化以后的getGirlName():
public String getGirlName1(Boy boy){
if(boy != null){
Girl girl = boy.getGirl();
if(girl != null){
return girl.getName();
}
}
return null;
}
@Test
public void test4(){
Boy boy = new Boy();
boy = null;
String girlName = getGirlName1(boy);
System.out.println(girlName);
}
//使用Optional类的getGirlName():
public String getGirlName2(Boy boy){
Optional<Boy> boyOptional = Optional.ofNullable(boy);
//此时的boy1一定非空
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();
}
@Test
public void test5(){
Boy boy = null;
boy = new Boy();
boy = new Boy(new Girl("苍老师"));
String girlName = getGirlName2(boy);
System.out.println(girlName);
}
}
java9新特性-了解
目录结构的改变

模块化系统: Jigsaw -> Modularity
jShell命令

String存储结构变更

java10新特性-了解
局部变量类型推断

集合新增创建不可变集合的方法
//示例1:
var list1 = List.of("Java", "Python", "C");
var copy1 = List.copyOf(list1);
System.out.println(list1 == copy1); // true
//示例2:
var list2 = new ArrayList<String>();
var copy2 = List.copyOf(list2);
System.out.println(list2 == copy2); // false
//示例1和2代码基本一致,为什么一个为true,一个为false?
从 源 码 分 析 , 可 以 看 出 copyOf 方 法 会 先 判 断 来 源 集 合 是 不 是
AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创
建一个新的集合。
示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,
所以 copyOf 方法又创建了一个新的实例,所以为false。
注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、
排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。
java11新特性-了解
ZGC

本文深入介绍了Java 8到11的主要新特性,包括Lambda表达式的使用、函数式接口、方法引用、构造器引用,以及Stream API的操作如筛选、映射、排序。此外,还详细讲解了Optional类的使用,以避免空指针异常,并探讨了Java 9的模块化系统和Java 10、11的局部变量类型推断及不可变集合创建方法。通过对这些特性的理解,有助于提升Java编程的效率和代码质量。

被折叠的 条评论
为什么被折叠?



