JDK8新特性
JDK8新特性
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表达式举例与语法.
- Lambda表达式的使用举例:
(o1,o2) -> Integer.compare(o1,o2); - Lambda表达式的格式举例:
- : lambda操作符或箭头操作符
- 的左边: lambda 形参列表,对应着要重写的接口中的抽象方法的形参列表。
- 的右边: lambda体,对应着接口的实现类要重写的方法的方法体。
- Lambda表达式的本质:
- 一方面,lambda表达式作为接口的实现类的对象。
- "万事万物皆对象">另一方面,lambda表达式是一个匿名函数。
//语法格式一:无参,无返回值
public void test2() {
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("我爱中国2");
}
};
r2.run();
}
//Lambda表达式的写法
public void test1() {
Runnable r1 = () -> System.out.println("我爱中国1");
r1.run();
}
public void test3() {
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(com1.compare(23, 25));
}
//Lambda表达式的写法
//语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
//语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
public void test4() {
Comparator<Integer> com1 = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(com1.compare(23, 25));
}
//方法引用
public void test5() {
Comparator<Integer> com1 = Integer::compare;
System.out.println(com1.compare(63, 25));
}
//若只需要一个参数时,参数的小括号可以省略
public void test6(){
Consumer<String> consumer1=s -> System.out.println(s);
consumer1.accept("时间你好");
}
5.函数式接口:
5.1 什么是函数式接口?为什么需要函数式接口?
- 如果接口中只声明有一个抽象方法,则此接口就称为函数式接口。
- 因为只有给函数式接口提供实现类的对象时,我们才可以使用lambda表达式。
5.2 api中函数式接口所在的包
jdk8中声明的函数式接口都在java.util.function包下。
02-方法引用.
1.举例;
Integer : : compare;
2.方法引用的理解
-
方法引用,可以看做是基于lambda表达式的进一步刻画。
-
当需要提供一个函数式接口的实例时,我们可以使用lambda表达式提供此实例。
当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。
3.方法引用的本质:
方法引用作为了函数式接口的实例。 --->“万事万物皆对象”
4.格式:
类(或对象)::方法名
5.具体使用情况说明;
情况1: 对象 ∶: 实例方法
- 要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同(或一致)(能装箱或父类)
- 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
- 注意:此方法b是非静态的方法,需要对象调用。
//1
public void test1() {
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("aaaaaaa");
//2. lambda表达式
Consumer<String> con2 = (String s) -> System.out.println(s);
con2.accept("bbbbbbbb");
//3.方法引用
//PrintStream printStream=System.out;
Consumer<String> con3 = System.out::println;
con3.accept("ccccccccc");
}
// Supplier中的T get()
//Employee中的String getName()
public void test2() {
//1
Person person = new Person("马化腾", 22);
Supplier<String> sup1=new Supplier<String>() {
@Override
public String get() {
return person.getName();
}
};
System.out.println(sup1.get());
//2
Supplier<String> sup2=()-> person.getName();
System.out.println(sup2.get());
//3
Supplier<String> sup3=person::getName;
System.out.println(sup3.get());
}
情况2: 类 :: 静态方法
- 要求:函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同。(或一致)
- 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
- 注意:此方法b是静态的方法,需要类调用。
//情况二:类::静态方法
// comparator中的int compare(T t1,T t2 )
// Integer中的int compare(T t1,T t2)
public void test3(){
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,11));
//2
Comparator<Integer> com2=(o1, o2)->Integer.compare(o1,o2);
System.out.println(com2.compare(12,11));
//3
Comparator<Integer> com3=Integer::compare;
System.out.println(com3.compare(12,11));
}
//Function中的Rapply(T t)
// Math中的Long round (Double d)
public void test4(){
Function<Double,Long> fun1=new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
System.out.println(fun1.apply(5.1));
//2
Function<Double,Long> fun2=aDouble->Math.round(aDouble);
System.out.println(fun2.apply(5.9));
//3
Function<Double,Long> fun3=Math::round;
System.out.println(fun3.apply(5.9));
}
情况3: 类 :: 实例方法
- 要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型相同。
- 同时,抽象方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第1个参数作为方法b的调用者,且抽象方法a的后n-1个参数与方法b的n-1个参数的类型相同(或一致)。则可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖
- 注意:此方法b是非静态的方法,需要对象调用。但是形式上,写出对象a所属的类
//情况三:类:︰实例方法(难)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
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", "cbc"));
//2
Comparator<String> com2=(o1,o2)->o1.compareTo(o2);
System.out.println(com2.compare("abc", "cbc"));
//3
Comparator<String> com3=String::compareTo;//因为方法调用者是形参,所以用其类表示
System.out.println(com3.compare("abc", "cbc"));
}
//BiPredicate中的boolean test(T t1,T t2);
// String中的boolean t1.equals(t2)
public void test6(){
BiPredicate<String,String> bip1=new BiPredicate<String, String>() {
@Override
public boolean test(String s, String s2) {
return s.equals(s2);
}
};
System.out.println(bip1.test("aa","aa"));
//2
BiPredicate<String,String> bip2=(s, s2)->s.equals(s2);
System.out.println(bip2.test("aa","aa"));
//3
BiPredicate<String,String> bip3=String::equals;
System.out.println(bip3.test("aa","aa"));
}
03-构造器引用、数组引用
1.构造器引用
1.1格式:类名 : : new
1.2说明:
- 调用了类名对应的类中的某一个确定的构造器
- 具体调用的是类中的哪一个构造器呢?取决于函数式接口的抽象方法泛型的形参列表!
//构造器引用
//Supplier中的T get()
public void test7(){
//1
Supplier<Person> sup1 =new Supplier<Person>() {
@Override
public Person get() {
return new Person("ooo",2);
}
};
System.out.println(sup1.get());
//2
Supplier<Person> sup2 =()->new Person("ooo",2);
System.out.println(sup2.get());
//3
Supplier<Person> sup3 =Person::new ;//根据泛型,只能调用空参的
System.out.println(sup3.get());
}
//BiFunction中的Rapply(T t,u u)
public void test8(){
BiFunction<String,Integer,Person> f1=new BiFunction<String, Integer, Person>() {
@Override
public Person apply(String s, Integer integer) {
return new Person(s,integer);
}
};
System.out.println(f1.apply("pp",22));
//3
BiFunction<String,Integer,Person> f2=Person::new;
System.out.println(f2.apply("pp",22));
}
2.数组引用
格式:数组名[]:: new
//数组引用
//Function中的Rapply(T t)
public void test9() {
Function<Integer,Person[]> f1=new Function<Integer, Person[]>() {
@Override
public Person[] apply(Integer integer) {
return new Person[integer];
}
};
//3
Function<Integer,Person[]> f2=Person[]::new;
}
}
5.Java8新特性:强大的Stream API
1 stream APIvs集合框架
- Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU的。集合关注的数据的存储,向下内存的。
- Stream API之于集合,类似于SQL之于数据表的查询。
2.使用说明
- stream自己不会存储元素。
- Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结界。
- stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。
stream执行流程步骤
1: Stream的实例化步骤
//创建Stream方式一:通过集合
public void test1(){
List<Student> list = StudentList.getStudent();
//default Stream<E> stream() :返回一个顺序流
Stream<Student> stream = list.stream();
//default Stream<E> parallelStream() :返回一个并行流
Stream<Student> stream1 = list.parallelStream();
System.out.println(stream);//java.util.stream.ReferencePipeline$Head@36baf30c
System.out.println(stream1);//java.util.stream.ReferencePipeline$Head@7a81197d
}
//创建Stream方式二:通过数组
public void test2(){
// 调用Arrays类的static <T> Stream<T> stream(T[ ] array):返回一个流
Integer[] integers = {1, 2, 3, 4, 5};
Stream<Integer> stream = Arrays.stream(integers);
System.out.println(stream);
}
//创建Stream方式三:通过Stream的of()
public void test3(){
Stream<String> stream = Stream.of("aa", "bb", "ccc", "pp");
}
2:一系列的中间操作步骤
package com.xin.lambda.demo02;
import java.util.Objects;
public class Student {
private int id;
private String name;
private int age;
private double wage;
public Student() {
}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student(int id, String name, int age, double wage) {
this.id = id;
this.name = name;
this.age = age;
this.wage = wage;
}
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 getWage() {
return wage;
}
public void setWage(double wage) {
this.wage = wage;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", wage=" + wage +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return id == student.id && age == student.age && Double.compare(student.wage, wage) == 0 && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age, wage);
}
}
========
package com.xin.lambda.demo02;
import java.util.ArrayList;
import java.util.List;
public class StudentList {
public static List<Student> getStudent(){
ArrayList<Student> list = new ArrayList<>();
list.add(new Student(1001,"aaa",22,8888));
list.add(new Student(1002,"bbb",11,5485));
list.add(new Student(1003,"ccc",58,2212));
list.add(new Student(1004,"dddd",47,2225));
list.add(new Student(1005,"eee",15,9999));
return list;
}
}
==========
package com.xin.lambda.demo02;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Day91401 extends TestCase {
//1-筛选与切片
public void test1() {
//filter(Predicate p)——接收Lambda,从流中排除某些元素。
// 练习:查询员工表中薪资大于7000的员工信息
List<Student> list = StudentList.getStudent();
Stream<Student> stream = list.stream();
stream.filter(s -> s.getWage() > 7000).forEach(System.out::println);
System.out.println();
//limit(n)--截断流,使其元素不超过给定数量。
//错误的。因为stream已经执行了终止操作,就不可以再调用其它的中间操作或终止操作了。
//stream.limit(1).forEach(System.out::println);
list.stream().filter(s -> s.getAge() > 20).limit(2).forEach(System.out::println);
System.out.println();
//skip(n)--跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。
list.stream().skip(2).forEach(System.out::println);
System.out.println();
//distinct()--筛选,通过流所生成元素的 hashCode() 和equals()去除重复元素
list.add(new Student(1055, "oooo", 55, 7777));
list.add(new Student(1055, "oooo", 55, 7777));
list.add(new Student(1055, "oooo", 55, 7777));
// System.out.println(list);
list.stream().distinct().forEach(System.out::println);
}
//2 映射
public void test2() {
//map(Function f)--接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素
// 练习:转换为大写
List<String> list = Arrays.asList("aa", "bb", "vv", "yy");
//方式1
//list.stream().map(s->s.toUpperCase()).forEach(System.out::println);
//方式2
list.stream().map(String::toUpperCase).forEach(System.out::println);
//练习:获取员工姓名长度大于3的员工的姓名。
List<Student> list1 = StudentList.getStudent();
Stream<Student> stream = list1.stream();
// stream.filter(s->s.getName().length()>3).map(s->s.getName()).forEach(System.out::println);
// stream.map(s->s.getName()).filter(n->n.length()>3).forEach(System.out::println);
stream.map(Student::getName).filter(n -> n.length() > 3).forEach(System.out::println);
}
//3-排序
public void test3() {
//sorted()--自然排序
Integer[] arr = {45, 978, 45, 22, 1, 56, 34, 77};
String[] arr1={"ss","ii","oo","aa"};
Arrays.stream(arr).sorted().forEach(System.out::println);
System.out.println(Arrays.toString(arr));//arr数组并没有因为升序,做调整。
Arrays.stream(arr1).sorted(String:: compareTo).forEach(System.out::println);
}
public void test4(){
// sorted(Comparator com)——定制排序
List<Student> list = StudentList.getStudent();
list.stream().sorted((s1,s2)->s1.getAge()-s2.getAge()).forEach(System.out::println);
}
}
3:执行终止操作
//1-匹配与查找
public void test1() {
// allMatch(Predicate p)——检查是否匹配所有元素。
//练习:是否所有的员工的年龄都大于18
List<Student> list = StudentList.getStudent();
System.out.println(list.stream().allMatch(student -> student.getAge() > 18));
//anyMatch(Predicate p)—-检查是否至少匹配一个元素。
// 练习:是否存在员工的工资大于8888
System.out.println(list.stream().anyMatch(student -> student.getWage() > 8888));
//findFirst—-返回第一个元素
System.out.println(list.stream().findFirst());//Optional[Student{id=1001, name='aaa', age=22, wage=8888.0}]
}
public void test2() {
//count——返回流中元素的总个数
List<Student> list = StudentList.getStudent();
System.out.println(list.stream().count());
//max(Comparator c)─-返回流中最大值
////练习:返回最高工资的员工
System.out.println(list.stream().max((s1, s2) -> Double.compare(s1.getWage(), s2.getWage())));
// System.out.println(list.stream().max((s1, s2) -> (int) (s1.getWage()-s2.getWage())));
// 练习:返回最高的工资:
//System.out.println(list.stream().max((s1, s2) -> Double.compare(s1.getWage(), s2.getWage())).get().getWage());
// System.out.println(list.stream().map(student -> student.getWage()).max((w1,w2)->Double.compare(w1,w2)));
System.out.println(list.stream().map(student -> student.getWage()).max(Double::compareTo));
//min(Comparator c)--返回流中最小值练习:返回最低工资的员工
System.out.println(list.stream().map(student -> student.getWage()).min(Double::compareTo));
//forEach(Consumer c)—-内部迭代
list.stream().forEach(System.out::println);
//针对于集合,jdk8中增加了一个遍历的方法
list.forEach(System.out::println);
//针对于List来说,遍历的方式:①使用Iterator增强for一般for ④ forEach()
}
//归约
public void test3(){
//reduce(T identity,BinaryOperator)--可以将流中元素反复结合起来,得到一个值。返回
// 练习1:计算1-10的自然数的和
List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8,9);
System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2));//45
System.out.println(list.stream().reduce(10, (x1, x2) -> x1 + x2));//55
System.out.println(list.stream().reduce(0, (x1, x2) -> Integer.sum(x1,x2)));
System.out.println(list.stream().reduce(0,Integer::sum));
//reduce(Binary0perator)--可以将流中元素反复结合起来,得到一个值。返回0ptional<T>
// 练习2:计算公司所有员工工资的总和
List<Student> list1 = StudentList.getStudent();
// System.out.println(list1.stream().map(s -> s.getWage()).reduce((w1, w2) -> Double.sum(w1, w2)).get());
System.out.println(list1.stream().map(s -> s.getWage()).reduce( Double::sum));
}
//收集
public void test4(){
//collect(Collector c)--将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
// 练习1:查找工资大于6000的员工,结果返回为一个List或Set
List<Student> list = StudentList.getStudent();
List<Student> list1 = list.stream().filter(student -> student.getWage() > 3000).collect(Collectors.toList());
//System.out.println(list1);
list1.forEach(System.out::println);
System.out.println();
//练习2:按照员工的年龄进行排序,返回到一个新的List中
List<Student> list2 = list.stream().sorted((s1, s2) -> s1.getAge() - s2.getAge()).collect(Collectors.toList());
list2.forEach(System.out::println);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?