java学习笔记16——java8的其他新特性
Java 8新特性简介
总结:
1.截止目前,JDK比较重要的时间节点和版本说明 1996 JDK1.0 2004 JDK5.0 最重要的一个里程碑式的版本 2014 JDK8.0 排第二的里程碑式的版本---> LTS 2017.9 JDK9.0 从此版本开始,每半年发布一个新的版本 2018.9 JDK11 ----> LTS 2021.9 JDK17 ----> LTS 2.如何学习新特性? > 角度1:新的语法规则(多关注) 自动装箱、自动拆箱、注解、enum、Lambda表达式、方法引用、switch表达式、try-catch变化、record等 > 角度2:增加、过时、删除API StringBuilder、ArrayList、新的日期时间的API、Optional等 > 角度3:底层的优化、JVM参数的调整、GC的变化、内存结构(永久代--->元空间)
Lambda 表达式
总结:
1.Lambda表达式的使用举例: (o1,o2)->Integer.compare(o1,o2); 2.Lambda表达式的格式举例: 3.Lambda表达式的格式: -> : lambda操作符或箭头操作符 -> 的左边: lambda形参列表,对应着要重写的接口中的抽象方法的形参列表。 -> 的右边: lambda体,对应着接口的实现类要重写的方法的方法体。 4.Lambda表达式的本质: > 一方面,lambda表达式作为接口的实现类的对象。 ----> "万事万物皆对象 > 另一方面,lambda表达式是一个匿名函数。 5.函数式接口: 5.1 什么是函数式接口?为什么需要函数式接口? > 如果接口中只声明有一个抽象方法,则此接口就称为函数式接口。 > 因为只有给函数式接口提供实现类的对象时,我们才可以使用lambda表达式。 5.2 api中函数式接口所在的包 jdk8中声明的函数式接口都在java.util.function包下 5.3 4个基本的函数式接口 接口 对应的抽象方法 消费型接口:Consumer<T> void accept(T t) 供给型接口:Supplier<T> T get() 函数型接口:Function<T,R> R apply(T t) 判断型接口:Predicate<T> boolean test(T t) 6.Lambda表达式的语法规则总结 -> 的左边:lambda形参列表,参数的类型都可以省略。如果形参只有一个,则一对()也可以省略。 -> 的右边:lambda体,对应着重写的方法的方法体。如果方法体中只有一行执行语向,则一对{}可以省略。 如果有return关键字,则必须一并省略。
代码:
public class LambdaTest {
@Test
public void test1(){
Runnable r1 = new Runnable(){
@Override
public void run() {
System.out.println("我爱北京天安门");
}
};
r1.run();
System.out.println("*******************");
//Lambda表达式的写法:
Runnable r2 = () -> {
System.out.println("我爱上海东方明珠");
};
r2.run();
}
@Test
public void test2(){
Comparator<Integer> com1 = new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare1 = com1.compare(12,21);
System.out.println(compare1); //-1
System.out.println("*************************");
//Lambda表达式的写法
Comparator<Integer> com2 = (Integer o1, Integer o2)->Integer.compare(o1,o2);
int compare2 = com2.compare(23,21);
System.out.println(compare2); //1
System.out.println("*****************");
//方法引用
Comparator<Integer> com3 = Integer :: compare;
int compare3 = com3.compare(23,21);
System.out.println(compare3); //1
}
}
代码2:
public class LambdaTest1 {
//语法格式一:无参,无返回值
@Test
public void test1() {
Runnable r1 = new Runnable() {
public void run() {
System.out.println("我爱北京天安门");
}
};
r1.run();
System.out.println("*****************");
Runnable r2 = () -> {
System.out.println("我爱北京天安门");
};
r2.run();
}
//语法格式二:Lambda需要一个参数,但是没有返回值
@Test
public void test2() {
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("谎言和誓言的区别是什么?");
System.out.println("***************");
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("一个是说的人当真了,一个是听的人当真了");
}
//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test
public void test3() {
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
con1.accept("如果大学可以重来,你最想重来的事是啥?");
System.out.println("********************");
Consumer<String> con2 = (s) -> {
System.out.println(s);
};
con1.accept("谈一场轰轰烈烈的爱情");
}
@Test
public void test3_1() {
int[] arr = {1, 2, 3, 4, 5}; //类型推断
HashMap<String, Integer> map = new HashMap<>(); //类型推断
var entrySet = map.entrySet();//类型推断,在jdk10及之后可以用
}
//语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
@Test
public void test4() {
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
con1.accept("世界那么大,我想去看看");
System.out.println("****************");
Consumer<String> con2 = s -> {
System.out.println(s);
};
con1.accept("世界那么大,我想去看看");
}
//语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test
public void test5() {
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println(com1.compare(12, 21));
System.out.println("**********************");
Comparator<Integer> com2 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com1.compare(12, 21));
}
//语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
@Test
public void test6(){
Comparator<Integer> com1 = (o1,o2)->{
return o1.compareTo(o2);
};
System.out.println(com1.compare(12, 21));
System.out.println("**************");
Comparator<Integer> com2 = (o1,o2)-> o1.compareTo(o2);
}
}
function文件:
public class MyFunctionalInterfaceTest {
@Test
public void test1(){
MyFunctionalInterface m = () -> System.out.println("hello");
m.method();
}
}
@FunctionalInterface
public interface MyFunctionalInterface {
void method();
// void method1();
}
函数式接口
方法引用与构造器引用
方法引用总结:
1.举例: Integer :: compare; 2.方法引用的理解 > 方法引用,可以看做是基于lambda表达式的进一步刻画。 > 当需要提供一个函数式接口的实例时,我们可以使用lambda表达式提供此实例。 > 当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。 3.方法引用的本质: 方法引用作为了函数式接口的实例。 ---> "万事万物皆对象" 4.格式: 类(或对象)::方法名 5.具体使用情况说明 情况1:对象::实例方法 要求:函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同。 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。 注意:此方法b是非静态的方法,需要对象调用。 情况2:类::静态方法 要求:函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同(或一致)。 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。 注意:此方法b是静态的方法,需要类调用。 情况3:类 ::实例方法 要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型相同。 同时,抽象方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第1个参数作为方法b的调用者,且抽象方法a 的后n-1个参数与方法b的n-1个参数的类型相同(或一致)。则可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。 注意:此方法b是非静态的方法,需要对象调用。但是形式上,写出对象a所属的类
构造器数组引用总结:
1.构造器引用 1.1 格式: 类名 :: new 1.2 说明: > 调用了类名对应的类中的某一个确定的构造器 > 具体调用的是类中的哪一个构造器呢?取决于函数式接口的抽象方法的形参列表! 2.数组引用 格式: 格式:数组名[]::new
代码:
data文件
Employee
public class Employee {
int id;
String name;
int age;
double salary;
public Employee() {
}
public Employee(int id) {
this.id = id;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
// @Override
// public boolean equals(Object o) {
// if (o == null || getClass() != o.getClass()) return false;
// Employee employee = (Employee) o;
// return id == employee.id && age == employee.age && Double.compare(salary, employee.salary) == 0 && Objects.equals(name, employee.name);
// }
//
// @Override
// public int hashCode() {
// return Objects.hash(id, name, age, salary);
// }
@Override
public boolean equals(Object o) {
if(this == o)
return true;
if(o==null||getClass()!=o.getClass())
return false;
Employee employee = (Employee)o;
if(id!=employee.id)
return false;
if(age!=employee.age)
return false;
if(Double.compare(employee.salary,salary)!=0)
return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31*result+(name!=null?name.hashCode():0);
result = 31*result+age;
temp = Double.doubleToLongBits(salary);
result = 31*result+(int)(temp^(temp>>>32));
return result;
}
}
EmployeeDate
public class EmployeeDate {
public static List<Employee> getEmployees() {
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001, "马化腾", 34, 6000.38));
list.add(new Employee(1002, "马云", 2, 19876.12));
list.add(new Employee(1003, "刘强东", 33, 3000.82));
list.add(new Employee(1004, "雷军", 26, 7657.37));
list.add(new Employee(1005, "李彦宏", 65, 5555.32));
list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
list.add(new Employee(1007, "任正非", 26, 4333.32));
list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
return list;
}
}
方法引用代码:
public class MethodRefTest {
//情况一:类(或对象)::方法名
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
@Test
public void test1() {
//1.
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("hello!");
//2.lambda表达式
Consumer<String> con2 = s -> System.out.println(s);
con2.accept("hello!");
//3.方法引用
PrintStream ps = System.out;
Consumer<String> con3 = ps::println;
con3.accept("hello!");
}
//Supplier中的T get()
//Employee中的String getName()
@Test
public void test2() {
Employee emp = new Employee(1001, "马化腾", 34, 6000.38);
//1.
Supplier<String> sup1 = new Supplier<String>() {
@Override
public String get() {
return emp.getName();
}
};
System.out.println(sup1.get());
//2.lambda表达式
Supplier<String> sup2 = () -> emp.getName();
System.out.println(sup2.get());
//3.方法引用
Supplier<String> sup3 = emp::getName;
System.out.println(sup3.get());
}
//情况二:类 :: 静态方法
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
@Test
public void test3() {
//1.
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(com1.compare(12, 21));
//2.
Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(com2.compare(21, 34));
//3.方法引用
Comparator<Integer> com3 = Integer::compare;
System.out.println(com3.compare(34, 34));
}
//Function中的R apply(T t)
//Math中的Lang round(Double d)
@Test
public void test4() {
//1.
Function<Double, Long> fun1 = new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
//2.
Function<Double, Long> fun2 = aDouble -> Math.round(aDouble);
//3.方法引用
Function<Double, Long> fun3 = Math::round;
}
//情况三:类 ::实例方法(难)
//Comparator中的int compare(T t1,T t2)
//String中的int t1.compareTo(t2)
@Test
public void test5() {
//1.
Comparator<String> com1 = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
System.out.println(com1.compare("abc", "abb"));
//2.
Comparator<String> com2 = (s1, s2) -> s1.compareTo(s2);
System.out.println(com2.compare("abc", "abb"));
//3.
Comparator<String> com3 = String::compareTo;
System.out.println(com3.compare("abc", "abb"));
}
//BiPredicate中的boolean test(T t1,T t2)
//String中的boolean t1.equals(t2)
@Test
public void test6() {
BiPredicate<String,String> biPre1 = new BiPredicate<String, String>() {
@Override
public boolean test(String s1,String s2){
return s1.equals(s2);
}
};
//2.
BiPredicate<String,String> biPre2 = (s1,s2) -> s1.equals(s2);
//3.方法引用
BiPredicate<String,String> biPre3 = String :: equals;
}
//Function中的R apply(T t)
//Employee中的String getName()
@Test
public void test7(){
Employee emp = new Employee(1001, "马化腾", 34, 6000.38);
//1
Function<Employee,String> fun1 = new Function<Employee,String>(){
@Override
public String apply(Employee employee) {
return employee.getName();
}
};
System.out.println(fun1.apply(emp));
//2.
Function<Employee,String> fun2 = employee -> employee.getName();
System.out.println(fun2.apply(emp));
//3.方法引用
Function<Employee,String> fun3 = Employee :: getName;
System.out.println(fun3.apply(emp));
}
}
构造器引用代码:
public class ConstructorRefTest {
//构造器引用
//Supplier中的T get()
@Test
public void test1(){
//1.
Supplier<Employee> sup1 = new Supplier<Employee>(){
@Override
public Employee get() {
return new Employee();
}
};
System.out.println(sup1.get());
//2.方法引用
Supplier<Employee> sup2 = Employee :: new; //调用的是Employee类中空参的构造器
System.out.println(sup2.get());
}
//Function中的R apply(T t)
@Test
public void test2(){
//1.
Function<Integer,Employee> func1 = new Function<Integer,Employee>() {
@Override
public Employee apply(Integer id) {
return new Employee(id);
}
};
System.out.println(func1.apply(12));
//2.构造器引用
Function<Integer, Employee> func2 = Employee::new; //调用的是Employee类中参数是Integer/int类型的构造器
System.out.println(func2.apply(11));
}
//BiFunction中的R apply(T t,U u)
@Test
public void test3(){
//1.
BiFunction<Integer,String,Employee> func1 = new BiFunction<Integer, String, Employee>() {
@Override
public Employee apply(Integer id, String name) {
return new Employee(id,name);
}
};
System.out.println(func1.apply(10, "Tom"));
//2.
BiFunction<Integer, String, Employee> func2 = Employee::new; //调用的是Employee类中参数是Integer/int、String类型的构造器
System.out.println(func2.apply(11, "Tony"));
}
//数组引用
//Function中的R apply(T t)
@Test
public void test4(){
//1.
Function<Integer,Employee[]> func1 = new Function<Integer,Employee[]>(){
@Override
public Employee[] apply(Integer length) {
return new Employee[length];
}
};
System.out.println(func1.apply(10).length);
//2.
Function<Integer,Employee[]> func2 = Employee[]::new;
System.out.println(func2.apply(11).length);
}
}
强大的Stream API
强大的Stream API: Collectors
总结:
1.Stream API vs 集合框架 > Stream API 关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU的。 集合关注的数据的存储,向下内存的。 > Stream API 之于集合,类似于SQL之于数据表的查询。 2.使用说明 ① stream 自己不会存储元素。 ② stream 不会改变源对象。相反,他们会返回一个持有结果的新stream。 ③ stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结果 ④ Stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。 3.Stream 执行流程 步骤1:Stream的实例化 步骤2:一系列的中间操作 步骤3:执行终止操作
代码:
StreamAPITest
public class StreamAPITest {
//创建Stream方式一:通过集合
@Test
public void test1(){
List<Employee> list = EmployeeDate.getEmployees();
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = list.stream();
//default Stream<E> parallelStream(): 返回一个并行流
Stream<Employee> stream1 = list.parallelStream();
System.out.println(stream);
System.out.println(stream1);
}
//创建Stream方式二:通过数组
@Test
public void test2(){
//调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
Integer[] arr = new Integer[]{1,2,3,4,5};
Stream<Integer> stream = Arrays.stream(arr);
int[] arr1 = new int[]{1,2,3,4,5};
IntStream stream1 = Arrays.stream(arr1);
}
//创建Stream方式三:通过Stream的of()
@Test
public void test3(){
Stream<String> stream = Stream.of("AA", "BB", "CC", "SS", "DD");
System.out.println(stream);
}
}
代码2:
public class StreamAPITest1 {
//1-筛选与切片
@Test
public void test1(){
//filter(Predicate p)——接受Lambda,从流中排除某些元素
//练习:查询员工表中薪资大于7000的员工信息
List<Employee> list = EmployeeDate.getEmployees();
Stream<Employee> stream = list.stream();
stream.filter(emp -> emp.getSalary() > 7000).forEach(System.out::println);
System.out.println();
//limit(n)——截断流,使其元素不超过给定数量
//错误的,因为Stream已经执行了终止操作,就不可以再调用其他的中间操作或终止操作了
// stream.limit(2).forEach(System.out::println);
list.stream().limit(4).forEach(System.out::println);
System.out.println();
//获取薪资大于7000的前两个
list.stream().filter(emp->emp.getSalary()>7000).limit(2).forEach(System.out::println);
System.out.println();
//skip(n) —— 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit
list.stream().skip(5).forEach(System.out::println);
System.out.println();
//distinct()——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
list.add(new Employee(1009, "马斯克", 40, 12500.32));
list.add(new Employee(1009, "马斯克", 40, 12500.32));
list.add(new Employee(1009, "马斯克", 40, 12500.32));
list.add(new Employee(1009, "马斯克", 40, 12500.32));
list.stream().distinct().forEach(System.out::println);
}
//映射
@Test
public void test2(){
//map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上
//练习:转换成大写
List<String> list = Arrays.asList("aa","bb","cc","dd");
//方式1:
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
//方式2:
list.stream().map(String :: toUpperCase).forEach(System.out::println);
//练习:获取员工姓名长度大于3的员工
List<Employee> employees = EmployeeDate.getEmployees();
employees.stream().filter(emp->emp.getName().length()>3).forEach(System.out::println);
//练习:获取员工姓名长度大于3的员工姓名
//方式1:
employees.stream().filter(emp -> emp.getName().length() > 3).map(emp -> emp.getName()).forEach(System.out::println);
//方式2:
employees.stream().map(emp -> emp.getName()).filter(name -> name.length() > 3).forEach(System.out::println);
//方式3:
employees.stream().map(Employee::getName).filter(name->name.length()>3).forEach(System.out::println);
}
//3-排序
@Test
public void test3(){
//sorted()——自然排序
Integer[] arr = new Integer[]{345,3,64,3,46,7,3,34,65,68};
String[] arr1 = new String[]{"GG", "DD", "MM", "SS", "JJ"};
Arrays.stream(arr).sorted().forEach(System.out::println);
System.out.println(Arrays.toString(arr)); //arr数组并没有因为升序,被调整
Arrays.stream(arr1).sorted().forEach(System.out::println);
//因为Employee没有实现Comparable接口,所以报错!
// List<Employee> list = EmployeeDate.getEmployees();
// list.stream().sorted().forEach(System.out::println);
//sorted(Comparator com)——定制排序
List<Employee> list = EmployeeDate.getEmployees();
list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).forEach(System.out::println);
//针对于字符串从大到小排序
Arrays.stream(arr1).sorted((s1, s2) -> s1.compareTo(s2)).forEach(System.out::println);
Arrays.stream(arr1).sorted(String::compareTo).forEach(System.out::println);
}
}
代码3:
public class StreamAPITest2 {
//1-匹配与查找
@Test
public void test1(){
//allMatch(Predicate p)——检查是否匹配所有元素
//练习:是否所有的员工的年龄都大于18
List<Employee> list = EmployeeDate.getEmployees();
System.out.println(list.stream().allMatch(emp -> emp.getAge() > 18)); //false
//anyMatch(Predicate p)——检查是否至少匹配一个元素
//练习:是否存在年龄大于18岁的员工
System.out.println(list.stream().anyMatch(emp->emp.getAge()>18));
//练习:是否存在员工的工资大于10000
System.out.println(list.stream().anyMatch(emp -> emp.getSalary() > 10000));
//findFirst——返回第一个元素
System.out.println(list.stream().findFirst().get());
}
@Test
public void test2(){
//count——返回流中元素的总个数
List<Employee> list = EmployeeDate.getEmployees();
System.out.println(list.stream().count());
System.out.println(list.stream().filter(emp->emp.getSalary()>7000).count());
//max(Comparator c)———返回流中最大值
//练习:返回最高工资的员工
System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
//练习:返回最高的工资
//方式1:
System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).get().getSalary());
//方式2:
System.out.println(list.stream().map(emp -> emp.getSalary()).max((salary1, salary2) -> Double.compare(salary1, salary2)).get());
System.out.println(list.stream().map(emp->emp.getSalary()).max(Double::compare).get());
//min(Comparator c)——返回流中最小值
//练习:返回最低工资的员工
System.out.println(list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
//forEach(Consumer c)——内部迭代
list.stream().forEach(System.out::println);
//针对于集合,jdk8中增加了一个遍历的方法
list.forEach(System.out::println);
//针对于List来说,遍历的方式:①使用Iterator ②增强for ③一般for ④forEach()
}
//2-归约
@Test
public void test3(){
//reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
//练习1:计算1-10的自然数的和
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2));
System.out.println(list.stream().reduce(0, (x1, x2) -> Integer.sum(x1, x2)));
System.out.println(list.stream().reduce(0, Integer::sum));
System.out.println(list.stream().reduce(10,(x1,x2)->x1+x2));
//reduce(BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
// 练习2:计算公司所有员工工资的总和
List<Employee> employeeList = EmployeeDate.getEmployees();
employeeList.stream().map(emp -> emp.getSalary()).reduce((salary1, salary2) -> Double.sum(salary1, salary2));
employeeList.stream().map(emp -> emp.getSalary()).reduce(Double::sum);
}
//3-收集
@Test
public void test4(){
List<Employee> list = EmployeeDate.getEmployees();
//collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
//练习1:查找工资大于6000的员工,结果返回为一个List或Set
List<Employee> list1 = list.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toList());
list1.forEach(System.out::println);
//固定到了list当中,可以根据list做一些其他操作
System.out.println();
list.forEach(System.out::println);
System.out.println();
//练习2:按照员工的年龄进行排序,返回到一个新的List中
List<Employee> list2 = list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).collect(Collectors.toList());
list2.forEach(System.out::println);
}
}
Optional 类
总结:
JDK8的新特性,JDK9-11中新增了一些方法。 1.为什么需要0ptional类? 为了避免代码中出现空指针异常。 2.如何实例化? static <T> Optional<T> ofNullable(T value):用来创建一个Optional实例,value可能是空,也可能非空 3.常用方法
代码 :
public class OptionalTest {
@Test
public void test(){
String star = "迪丽热巴";
star = null;
//使用Optional避免空指针的问题
//1.实例化:
//ofNullable(T value):用来创建一个Optional实例,value可能是空,也可能非空
Optional<String> optional = Optional.ofNullable(star);
//orElse(t other):如果Optional实例内部的value属性不为null,则返回value,如果value为null
//则返回other
String otherStar = "杨幂";
String finalStar = optional.orElse(otherStar);
System.out.println(finalStar.toString());
}
@Test
public void test2(){
String star = "迪丽热巴";
// star = null;
Optional<String> optional = Optional.ofNullable(star);
//get():取出内部的value值
System.out.println(optional.get());
}
}
JDK 9 的发布
一、JDK 和 JRE 目录结构的改变
二、模块化系统: Jigsaw ——>Modularity
三、Java的REPL工具: jShell命令
四、语法改进:接口的私有方法
六、语法改进:try语句
七、String存储结构变更
八、集合工厂方法:快速创建只读集合
九、InputStream 加强
十、增强的 Stream API
十一、Optional获取Stream的方法
十二、Javascript引擎升级:Nashorn
Java 10 新特性
JDK10的12个JEP
一、局部变量类型推断
二、集合新增创建不可变集合的方法
Java 11 新特性
一、新增了一系列字符串处理方法
二、Optional 加强
三、局部变量类型推断升级
四、全新的HTTP 客户端API
五、更简化的编译运行程序
六、废弃Nashorn引擎
七、ZGC
八、其它新特性
总结及代码
jshell:
这是JDK9的新特性 1.命令行中通过指令jshell,调取jshell工具 2.常用指令: /help:获取关使用 jshell 工具的信息 /help intro : jshell 工具的简介 /list :列出当前 session 里所有有效的代码片段 /vars :查看当前 session 下所有创建过的变量 /methods :查看当前 session 下所有创建过的方法 /imports :列出导入的包 /history :键入的内容的历史记录 /edit :使用外部代码编辑器来编写 Java 代码 /exit :退出 jshell 工具
try-catch:
public class TryCatchTest {
/**
* 举例1:
* JDK7之前的写法
*/
@Test
public void test01() {
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter("test.txt");
bw = new BufferedWriter(fw);
bw.write("hello,世界");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw != null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 举例1:
* JDK7中的写法
*/
@Test
public void test02() {
try (FileWriter fw = new FileWriter("test.txt");
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write("hello,世界");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 举例2:从test.txt(utf-8)文件中,读取内容,写出到abc.txt(gbk)文件中
* JDK7之前的写法
*/
@Test
public void test03() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
br = new BufferedReader(isr);
FileOutputStream fos = new FileOutputStream("abc.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
bw = new BufferedWriter(osw);
String str;
while ((str = br.readLine()) != null) {
bw.write(str);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 举例2:从test.txt(utf-8)文件中,读取内容,写出到abc.txt(gbk)文件中
* JDK7中的写法
*/
@Test
public void test04() {
try (
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
BufferedReader br = new BufferedReader(isr);
FileOutputStream fos = new FileOutputStream("abc.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
BufferedWriter bw = new BufferedWriter(osw);
) {
String str;
while ((str = br.readLine()) != null) {
bw.write(str);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//jdk9中举例:
@Test
public void test05(){
InputStreamReader reader = new InputStreamReader(System.in);
OutputStreamWriter writer = new OutputStreamWriter(System.out);
try(reader;writer){
//reader、writer是final的,不可再被赋值
}catch(IOException e){
e.printStackTrace();
}
}
}
局部变量类型推断
这是JDK10的新特性。
public class VarTest {
//可以使用的场景
@Test
public void test01(){
//1.局部变量的实例化
var list = new ArrayList<String>();
var set = new LinkedHashSet<Integer>();
//2.增强for循环中的索引
for(var v:list){
System.out.println(v);
}
//3.传统for循环中
for(var i = 0;i<100;i++){
System.out.println(i);
}
//4.返回值类型含复杂泛型结构
var iterator = set.iterator();
HashMap<String,Integer> map = new HashMap<>();
var entrySet = new HashMap<>();
// Iterator<Map.Entry<Integer, Student>> iterator = set.iterator();
}
/**
* 声明一个成员变量
* 声明一个数组变量,并为数组静态初始化(省略new的情况下)
* 方法的返回值类型
* 方法的参数类型
* 没有初始化的方法内的局部变量声明
* 作为catch块中异常类型
* Lambda表达式中函数式接口的类型
* 方法引用中函数式接口的类型
*/
//声明一个成员变量
// var i;
// var j = 0;
@Test
public void test2(){
// 声明一个数组变量,并为数组静态初始化(省略new的情况下)
var arr = new int[]{1,2,3,4,5};
// var arr = {1,2,3,4,5};
}
//没有初始化的方法内的局部变量声明
//方法的参数类型
//方法的返回值类型
// public var method(int i,var m){
// var i = 0;
// }
@Test
public void test3(){
// try{
// System.out.println(10/0);
// }catch(var e){ //作为catch块中异常类型
// e.printStackTrace();
// }
//方法引用中函数式接口的类型
// var com = (s1,s2)->s1.compareTo(s2); //Lambda表达式中函数式接口的类型
}
}
instanceof模型匹配
JDK14中预览特性。 JDK15中第二次预览。 JDK16中转正特性。 JDK14之前: // 先判断类型 if(obj instanceof string){ // 然后转换 String s=(string)obj; // 然后才能使用 } JDK14:(自动匹配模式) if(obj instanceof string s){ //如果类型匹配 直接使用 }else { //如果类型不匹配则不能直接使用 }
public class InstanceOfTest {
/**
* 举例1:
* JDK14之前
*/
@Test
public void test1(){
Object obj = new String("hello,Java14");
if(obj instanceof String){
String str = (String)obj;
System.out.println(str.contains("Java"));
}else{
System.out.println("非String类型");
}
}
/**
* 举例1:
* JDK14中
*/
@Test
public void test2(){
Object obj = new String("hello,Java14");
if(obj instanceof String str){
System.out.println(str.contains("Java"));
}else{
System.out.println("非String类型");
}
}
}
/**
* 举例2:
*/
class Computer{
private String model; //型号
private double price;//价格
//方式1:
// public boolean equals(Object o){
// if(o instanceof Computer) {
// Computer other = (Computer)o;
// if(this.model.equals(other.model)&&this.price==other.price){
// return true;
// }
// }
// return false;
// }
//方式2:
// public boolean equals(Object o){
// if(o instanceof Computer other){
// return this.model.equals(other.model)&&this.price==other.price;
// }
// return false;
// }
public boolean equals(Object o) {
return o instanceof Computer other && this.model.equals(other.model) && this.price == other.price;
}
}
switch表达式
JDK12中预览特性:switch表达式 JDK13中二次预览特性:switch表达式 JDK14中转正特性:switch表达式 JDK17的预览特性:switch的模式匹配
public class SwitchPatternTest {
public static void main(String[] args){
System.out.println(formatter(12));
System.out.println(formatterSwitchPattern(12));
}
/**
* JDK17之前
*/
static String formatter(Object o){
String formatted = "unknown";
if(o instanceof Integer i){
formatted = "int" + i;
}else if(o instanceof Long l){
formatted = "long" + l;
}else if(o instanceof Double d){
formatted = "double" + d;
}else if(o instanceof String s){
formatted = "String" + s;
}
return formatted;
}
/**
* JDK17中switch的模式匹配
*/
static String formatterSwitchPattern(Object o){
String formatted = switch(o){
case Integer i:
yield "int" + i;
case Long l:
yield "long" + l;
case Double d:
yield "double" + d;
case String s:
yield "String" + s;
default:
yield o.toString();
};
return formatted;
}
}
enum Week{
MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}
public class SwitchExceptionTest {
/**
* 举例1:
* JDK12之前的写法
*/
@Test
public void test1(){
Week day = Week.FRIDAY;
int num=0;
switch(day){
case MONDAY:
num = 20;
System.out.println(1);
break;
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
num = 20;
System.out.println(2);
break;
case FRIDAY:
System.out.println(3);
break;
case SATURDAY:
case SUNDAY:
System.out.println(4);
break;
default:
throw new RuntimeException("What day is today?"+day);
}
}
/**
* 举例1:
* jdk12中的写法:switch表达式,省去了break语句,避免了因少写break而出现case穿透
*/
@Test
public void test2() {
Week day = Week.FRIDAY;
int num = 0;
switch (day) {
case MONDAY -> System.out.println(1);
case TUESDAY, WEDNESDAY, THURSDAY -> System.out.println(2);
case FRIDAY -> System.out.println(3);
case SATURDAY, SUNDAY -> System.out.println(4);
default -> throw new RuntimeException("What day is today?" + day);
}
}
/**
* 举例1:
* jdk12中的写法:还可以使用变量接收switch表达式的结果
*/
@Test
public void test3(){
Week day = Week.FRIDAY;
int num = 0;
int result = switch (day) {
case MONDAY -> 1;
case TUESDAY, WEDNESDAY, THURSDAY ->2;
case FRIDAY -> 3;
case SATURDAY, SUNDAY -> 4;
default -> throw new RuntimeException("What day is today?" + day);
};
System.out.println(result);
}
/**
* 举例1:(在default中返回值5)
* JDK13中的写法:引入了yield关键字,用于返回指定的数据,结束switch结构。
* 这意味着,switch表达式(返回值)应该使用yield,switch语句(不返回值)应该使用break。
* 和return的区别在于:return会直接跳出当前方法,而yield只会跳出当前switch块。
*/
@Test
public void test4(){
Week day = Week.FRIDAY;
int num = 0;
int result = switch (day) {
case MONDAY -> {
yield 1;
}
case TUESDAY, WEDNESDAY, THURSDAY -> {
yield 2;
}
case FRIDAY -> {
yield 3;
}
case SATURDAY, SUNDAY -> {
yield 4;
}
default -> {
System.out.println("值未找到");
yield 5;
}
};
System.out.println(result);
}
@Test
public void test5(){
Week day = Week.FRIDAY;
int num = 0;
int result = switch (day) {
case MONDAY:
yield 1;
case TUESDAY, WEDNESDAY, THURSDAY:
yield 2;
case FRIDAY:
yield 3;
case SATURDAY, SUNDAY:
yield 4;
default:
yield 5;
};
System.out.println(result);
}
}
block:
JDK13的预览特性 JDK14中二次预览特性 JDK15中功能转正
public class BlockTest {
//对比1:
@Test
public void test1() {
String info = "<html>\n" +
" <body>\n" +
" <p>Hello,尚硅谷</p>\n" +
" </body>\n" +
"</html>";
System.out.println(info);
}
@Test
public void test2() {
String info = """
<html>
<body>
<p>Hello,尚硅谷</p>
</body>
</html>
""";
System.out.println(info);
}
//对比2:
@Test
public void test3(){
String myJson = "{\n" +
" \"name\":\"Song Hongkang\",\n" +
" \"gender\":\"男\",\n" +
" \"address\":\"www.atguigu.com\"\n" +
"}";
System.out.println(myJson);
}
@Test
public void test4(){
String myJson1 = """
{
"name":"Song Hongkang",
"gender":"男",
"address":"www.atguigu.com"
}
""";
System.out.println(myJson1);
}
//对比3
@Test
public void test5(){
String query = "SELECT employee_id,last_name,salary,department_id\n"+
"FROM employees\n" +
"WHERE department_id IN (40,50,60)\n" +
"ORDER BY department_id ASC";
}
@Test
public void test6(){
String newQuery = """
SELECT employee_id,last_name,salary,department_id
FROM employees
WHERE department_id IN (40,50,60)
ORDER BY department_id ASC
""";
System.out.println(newQuery);
}
/**
* JDK14新特性:
* \:取消换行操作
* \s:表示一个空格
*/
@Test
public void test7(){
String newQuery1 = """
SELECT id,name,email \
FROM customers\s\
WHERE id > 4 \
ORDER BY email DESC
""";
System.out.println(newQuery1);
}
}
record:
JDK14中预览特性 JDK15中第二次预览特性 JDK16中转正特性
public class OrderTest {
@Test
public void test1(){
Order order1 = new Order(1001,"orderAA");
//测试toString()
System.out.println(order1);
//测试getter()
System.out.println(order1.orderId());
System.out.println(order1.orderName());
Order order2 = new Order(1001,"orderAA");
//测试equals()
System.out.println(order1.equals(order2));
//测试HashCode()和equals()
HashSet<Order> set = new HashSet<>();
set.add(order1);
set.add(order2);
System.out.println(set);
}
//测试Record
@Test
public void test2(){
Order1 order1 = new Order1(1001,"orderAA");
//测试toString()
System.out.println(order1);
//测试getter()
System.out.println(order1.orderId());
System.out.println(order1.orderName());
Order1 order2 = new Order1(1001,"orderAA");
//测试equals()
System.out.println(order1.equals(order2));
//测试HashCode()和equals()
HashSet<Order1> set = new HashSet<>();
set.add(order1);
set.add(order2);
System.out.println(set);
}
@Test
public void test3(){
Class<Person> clazz = Person.class;
System.out.println(clazz.getSuperclass());
}
}
Person
public record Person(int id, String name) {
//-还可以在record声明类中定义静态字段、静态方法、构造器或实例方法。
static String info = "我是一个人";
public static void show() {
System.out.println("我是一个人!");
}
public Person() {
this(0, null);
}
public void test() {
System.out.println("人吃饭");
}
//-不能在record声明的类中定义实例字段:类不能声明为abstract;不能声明显式的父类等。
// final int age;
}
//abstract record Dog(int id){}
//record Cat(int id) extends Thread{}
//class Student extends Person{} //record声明的类不能有子类
Order
public class Order {
//属性:private final修饰
private final int orderId;
private final String orderName;
//构造器中初始化属性
public Order(int orderId,String orderName){
this.orderId = orderId;
this.orderName = orderName;
}
//提供属性的getter方法
public int orderId() {
return orderId;
}
public String orderName() {
return orderName;
}
//equals()和hashCode()
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Order order = (Order) o;
return orderId == order.orderId && Objects.equals(orderName, order.orderName);
}
@Override
public int hashCode() {
return Objects.hash(orderId, orderName);
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderName='" + orderName + '\'' +
'}';
}
}
Order1
public record Order1(int orderId,String orderName) {
}
密封类的使用:
JDK15的预览特性J DK16二次预览特性 JDK17转正特性
//Person是一个密封类,可以被指定的子类所继承,非指定的类不能继承Person类
public sealed class Person permits Student, Teacher, Worker {
}
//要求指定的子类必须是final、sealed、non-sealed三者之一
final class Student extends Person {
} //Student类不能被继承了
sealed class Teacher extends Person permits SeniorTeacher {
} //Teacher类只能被指定的子类继承
non-sealed class SeniorTeacher extends Teacher{}
non-sealed class Worker extends Person {
} //Worker类在被继承时,没有任何限制
class WatchWorker extends Worker{}
//class Farmer extends Person{}