JDK8新特性
《Lambda表达式》
一、为什么要使用Lambda表达式
- 避免匿名内部类定义过多
- 让代码看起来简洁
- 去掉多余没有意义的代码
- 留下核心逻辑
- Lambda是在JDK1.8中产生的
二、理解Functional Interface(函数式接口)
-
函数式接口是学习Java8 lambda表达式的关键所在
-
函数式接口定义:
- 任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口
public interface Runnable{ public abstract void run(); //接口中默认方法为抽象方法,也可以不写abstract修饰符 }
- 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
Lambda演变史
(1)正常操作
public class TestLambdaImpl implements TestLambda{
@Override
public void lambda() {
System.out.println("I like Lambda");
}
public static void main(String[] args) {
TestLambdaImpl testLambda = new TestLambdaImpl();
testLambda.lambda();
}
}
interface TestLambda{
void lambda();
}
(2)静态内部类
public class TestLambdaImpl{
static class Test01Impl implements TestLambda{
@Override
public void lambda() {
System.out.println("静态内部类");
}
}
public static void main(String[] args) {
Test01Impl ti = new Test01Impl();
ti.lambda();
}
}
interface TestLambda{
void lambda();
}
(3)局部类
public class TestLambdaImpl{
public static void main(String[] args) {
class Test01Impl implements TestLambda{
@Override
public void lambda() {
System.out.println("局部类");
}
}
Test01Impl ti = new Test01Impl();
ti.lambda();
}
}
interface TestLambda{
void lambda();
}
(4)匿名内部类
没有类的名称,必须借助接口或者父类
public class TestLambdaImpl{
public static void main(String[] args) {
TestLambda testLambda = null;
testLambda= new TestLambda(){
@Override
public void lambda() {
System.out.println("匿名内部类");
}
};
testLambda.lambda();
}
}
interface TestLambda{
void lambda();
}
(5)Lambda表达式
public class TestLambdaImpl{
public static void main(String[] args) {
TestLambda testLambda = null;
testLambda = ()->{
System.out.println("Lambda表达式");
};
//也可以写成 "testLambda = ()->System.out.println("Lambda表达式");"
testLambda.lambda();
}
}
interface TestLambda{
void lambda();
}
《StreamAPI》
Stream流主要用在操作集合上,例如:
简单概述
- Stream就是操作容器的
实例化
方式一:
/**
* 通过集合获取Stream
*/
@Test
public void test01(){
List<Student> students = StudentData.getStudents();
Stream<Student> stream = null;
//返回顺序流
stream = students.stream();
//返回并行流
stream = students.parallelStream();
System.out.println(stream);
}
方式二:
/**
* 通过数组创建
*/
@Test
public void test02(){
int[] arr = new int[]{1,2,3,4,5,6};
IntStream stream = Arrays.stream(arr);
Student student01 = new Student(1002, "李四", 21, 65.0);
Student student02 = new Student(1003, "王五", 22, 75.0);
Student[] arr01 = new Student[]{student01,student02};
Stream<Student> stream1 = Arrays.stream(arr01);
}
方式三:
/**
* 通过Stream的of
*/
@Test
public void test03(){
Stream<String> stringStream = Stream.of("1", "2", "3");
}
中间操作
01.筛选与切片
-
filter(Predicate p):接收Lambda,从流中排除某些元素
@Test public void test01(){ List<Student> students = StudentData.getStudents(); //查询学生表中成绩大于70的 students.stream().filter(student -> student.getScope() > 70).forEach(System.out::println); }
-
distinct():筛选,通过流所生成的hashCode()和equals()去除重复元素
//去重(取出对象中所有数据均相同的数据) StudentData.getStudents().stream().distinct().forEach(System.out::println);
-
limit(long maxSize):截断流,使其元素不超过给定数量
//截断流,获取前三个 StudentData.getStudents().stream().limit(3).forEach(System.out::println);
-
skip(long n):跳过元素,返回一个扔掉前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
//跳过前三个,获取其他的 StudentData.getStudents().stream().skip(3).forEach(System.out::println);
02.排序
-
sorted:产生一个新流,其中按自然顺序排序
//自然排序 List<Integer> integers = Arrays.asList(1, 200, 34, 4, 556, 61); integers.stream().sorted().forEach(System.out::println);
-
sorted:产生一个新流,其中按比较器顺序排序
//定制排序(根据年龄排序) List<Student> students = StudentData.getStudents(); students.stream().sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);
03.映射
将字母变成大写
List<String> strings = Arrays.asList("aa", "bb", "cc", "dd");
strings.stream().map(str->str.toUpperCase()).forEach(System.out::println);
获取学生姓名大于3的姓名
StudentData.getStudents().stream().map(Student::getName).collect(Collectors.toList()).stream().filter(student01 -> student01.length()>3).forEach(System.out::println);
04.终止操作
import java.util.Optional;
public class StreamAPITest02 {
@Test
public void test01(){
/*
allMatch(Predicate p) 检查是否匹配所有元素
查询是否年龄均大于18
*/
boolean allMatch = StudentData.getStudents().stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
System.out.println();
/*
anyMatch(Predicate p) 检查是否至少匹配一个元素
查询是成绩是否有75分的
*/
boolean anyMatch = StudentData.getStudents().stream().anyMatch(e -> e.getScope()==65);
System.out.println(anyMatch);
System.out.println();
/*
noneMatch(Predicate p) 检查是否没有匹配的元素
查询是是否存在学生姓李
若存在则返回false,不存在返回true
*/
boolean noneMatch = StudentData.getStudents().stream().noneMatch(e -> e.getName().contains("李"));
System.out.println(noneMatch);
System.out.println();
/*
findFirst:返回第一个元素
*/
Optional<Student> first = StudentData.getStudents().stream().findFirst();
System.out.println(first);
System.out.println();
/*
count:返回流中的个数
*/
long count = StudentData.getStudents().stream().count();
System.out.println(count);
System.out.println();
/*
max:返回流中最大值
*/
Optional<Double> max = StudentData.getStudents().stream().map(e -> e.getScope()).max(Double::compareTo);
System.out.println(max.get());
System.out.println();
/*
min:返回流中最小值
*/
Optional<String> s = StudentData.getStudents().stream().min((e1, e2) -> Double.compare(e1.getScope(), e2.getScope())).map(Student::getName);
System.out.println(s.get());
}
}
归约
-
reduce(T iden,BinaryOperator* b*):可以将流中元素反复结合起来,得到一个值。返回T
/* 计算1-10的和 */ List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); System.out.println(integers.stream().reduce(0, Integer::sum).intValue());
/* 计算所有学生总成绩 */ Double reduce = StudentData.getStudents().stream().map(e -> e.getScope()).reduce((double) 0, Double::sum); System.out.println(reduce);
-
reduce(BinaryOperator b):可以将六种元素反复结合起来,得到一个值。返回Optional<T>
/* 计算总成绩 */ Optional<Double> reduce = StudentData.getStudents().stream().map(Student::getScope).reduce(Double::sum); System.out.println(reduce);
收集
-
Collector:收集为List集合或者Set集合
/* 查找成绩大于80的同学,返回结果一个List或set */ //返回List List<Student> collect = StudentData.getStudents().stream().filter(student -> student.getScope() > 80).collect(Collectors.toList()); collect.forEach(System.out::println); System.out.println(); //返回Set Set<Student> collect1 = StudentData.getStudents().stream().filter(student -> student.getScope() > 80).collect(Collectors.toSet()); collect1.forEach(System.out::println);
《TimeAPI》
在之前版本中,日期时间设计考虑不周。主要是非线程安全、时区处理麻烦
新版Java中,引入了如下API:
LocalDate:表示日期,包含:年月日。格式为:2020-01-13
LocalTime:表示时间,包含:时分秒。格式为:16:39:09.307
LocalDateTime:表示日期时间,包含:年月日 时分秒。格式为:2020-01-13T16:40:59.138
DateTimeFormatter:日期时间格式化类
Instant:时间戳类
Duration:用于计算 2 个时间(LocalTime,时分秒)之间的差距
Period:用于计算 2 个日期(LocalDate,年月日)之间的差距
ZonedDateTime:包含时区的时间
《接口增强》
在JDK8之前,JDK规定接口中只能定义 ①静态常量 ②抽象方法
修饰词 interface 接口名{
静态常量;
抽象方法;
}
在JDK8之后,对接口进行了增强。我们可以在接口中定义 ①静态常量 ②抽象方法 ③默认方法④静态方法
修饰词 interface 接口名{
静态常量;
抽象方法;
默认方法;
静态方法;
}
《重复注解》
在 Java 8 之前我们不能在同一个类、同一方法上重复使用同一个注解
@PropertySource("classpath:config1.properties")
@PropertySource("classpath:config2.properties")
public class AnnotationDemo{
//代码部分
}
上面的代码无法在 Java 7 下通过编译,错误是: Duplicate annotation。在 JDK 8 中引入了一个注解 @Repeatable 来标识某个注解是可被重复使用的,但是需要一个容器注解。可重复注解的使用步骤如下:
1.1定义可重复的注解容器注解
@Retention(RetentionPolicy.RUNTIME)
@interface MyTests {//这是重复的容器注解
MyTest[] value();
}
1.2定义一个可以重复的注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(MyTests.class)
@interface MyTest{
String value();
}
1.3配置多个重复的注解
@MyTest("mt1")
@MyTest("mt2")
@MyTest("mt3")
public class annotationDemo {
@Test
@MyTest("ms1")
@MyTest("ms2")
public void test(){
}
@Test
@MyTest("mn1")
@MyTest("mn2")
public void test(String name){
}
}
1.4解析配置的重复注解
@MyTest("mt1")
@MyTest("mt2")
@MyTest("mt3")
public class annotationDemo {
@Test
@MyTest("ms1")
@MyTest("ms2")
public void test(){
}
@Test
@MyTest("mn1")
@MyTest("mn2")
public void test(String name){
}
//4.解析配置的重复注解
public static void main(String[] args) throws NoSuchMethodException {
//4.1 获取类上的注解
//getAnnotationsByType() 是新增的API,用于用户获取重复的注解
MyTest[] annotationsByType = annotationDemo.class.getAnnotationsByType(MyTest.class);
for (MyTest myTest: annotationsByType) {
System.out.println("获取类上的注解:"+myTest.value());
}
//4.2 获取(无参方法)方法上的注解
//getAnnotationsByType() 是新增的API,用于用户获取重复的注解
MyTest[] tests = annotationDemo.class.getMethod("test", null).getAnnotationsByType(MyTest.class);
for (MyTest myTest: tests) {
System.out.println("获取(无参方法)方法上的注解:"+myTest.value());
}
//4.2 获取(有参方法)方法上的注解
//getAnnotationsByType() 是新增的API,用于用户获取重复的注解
MyTest[] tests1 = annotationDemo.class.getMethod("test", String.class).getAnnotationsByType(MyTest.class);
for (MyTest myTest: tests1) {
System.out.println("获取(有参方法)方法上的注解:"+myTest.value());
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库