首先介绍匿名内部类:必须是类或者接口,其中只有一个抽象方法。
new 类名(接口名)(){
重写抽象方法
}
//第一种方式
new Animal(){
public void eat(){
System.out.println("吃肉");
}
}.eat(); //整个是相当于是抽象类的子类对象,然后可以调用eat方法
//第二种方式
Animal A=new Animal(){ //相当于多态 父类引用指向子类对象
public void eat(){
System.out.println("吃肉");
}
}
a.eat();
Lambda表达式:
基础语法:箭头操作符或者叫Lambda操作符(->),将Lambda表达式拆分成两部分,左侧对应的是表达式的参数列表,右侧是表达式中所执行的功能(Lambda体)。Lambda左侧的参数列表就是对应接口中抽象方法的参数列表,右侧对应抽象方法的实现逻辑。
语法格式:
1、无参数、无返回值:()->System.out.println("你好");比如Runnable:
Runnable r=()-> System.out.println("hello world");
2、有一个参数,并且无返回值:举例:(若只有一个参数,那么参数的小括号可以省略不写)
public interface Consumer {
void accept(T t);
}
Consumer c=(x)-> System.out.println(x);
//Consumer c= x-> System.out.println(x);
c.accept("hhahaha");
3、有两个参数或者多个参数,并且Lambda体中有多条语句(Lambda体必须使用大括号),有返回值。
Comparator c=(x, y)->{
System.out.println("函数式接口");
return Integer.compare(x,y);
};
System.out.println(c.compare(5,3));
4、如果有两个参数并且有返回值,Lambda体中只有一条返回值,return和大括号都可以省略不写。
Comparator c=(x, y)->Integer.compare(x,y);
System.out.println(c.compare(5,3));
5、Lambda表达式的参数列表数据的数据类型可以省略不写。
Lambda表达式需要函数式接口的支持,接口中只有一个抽象方法的接口,可以使用一个注解使用@FunctionalInterface修饰一下,可以检查是不是函数式接口。
四大内置核心函数式接口
方法引用和构造器引用
方法引用:如果在Lambda中的内容有方法已经实现了,可以使用方法引用。
固定的格式:
对象::实例方法名;要求是抽象体中的方法中的参数列表和返回值类型和Lambda体中的参数列表和返回值类型是一样的。
PrintStream ps=System.out;
Consumer con=ps::println;
Consumer con=System.out::println;
类::静态方法名;
Comparator接口中有一个抽象方法compare(), int compare(T o1, T o2);和Lambda表达式中的(实现类中)方法的参数列表和返回值类型是一致的:
public final class Integer extends Number implements Comparable {
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
....
}
---------------------------------------------
举例:
Comparator com=(x,y)->Integer.compare(x,y);
Comparator com1=Integer::compare;
类::实例方法名
如果说在Lambda中第一个参数是方法的调用者,第二个参数是被调用方法的参数时,可以使用类:实例方法名。x.equals(y).
构造器引用:类名::new;==(new Person()),自动匹配符合的构造器。
数组引用:type[]::new; (String[]::new;)
Stream流
介绍:在util包中
Stream是处理集合的关键抽象概念,他可以指定你希望对集合处理的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用StreamAPI堆积和数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用StreamAPI类执行并行操作。
流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。集合讲的是数据、流讲的是计算。Stream自己不会存储元素。Stream不会改变源对象,相反他们会返回一个持有结果的新Stream。Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
操作步骤:
创建Stream:有四种形式
1、可以通过collection系列集合提供的stream()或者parallelStream()
List list=new ArrayList<>();
Stream stream = list.stream();
2、通过Arrays中的静态方法获取数组流
String[] str=new String[10];
Stream stream1 = Arrays.stream(str);
3、通过Stream类中的静态方法of(),也可以传递数组
Stream stream3 = Stream.of("aa");
4、创建无限流,
迭代:第一个参数是seed种子,也就是起始值,第二个参数是操作
Stream stream4 = Stream.iterate(0, (x) -> x + 2);
生成:
Stream stream5 = Stream.generate(() -> Math.random());
中间操作:没有任何效果,必须有终止操作
List list=Arrays.asList(
new Person("a",10),
new Person("b",20),
new Person("c",30),
new Person("d",40),
new Person("e",50),
new Person("f",60)
);
筛选和切片:
filter()-》接收Lambda,从流中排除某些元素
list.stream()
.filter((p)->p.getAge()>20)
.forEach(System.out::println);
}
limit()-》截断流,使其元素不超过给定数量
list.stream()
.filter((p)->p.getAge()>20)
.limit(2)
.forEach(System.out::println);
}
distinct()-》筛选,通过流所生成元素的hashCode()和equals()去除重复元素
skip()-》跳过元素,返回一个扔掉前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补。
list.stream()
.filter((p)->p.getAge()>20)
.skip(2) //扔掉前两个
.forEach(System.out::println);
映射:
map()-》接收Lambda,将元素转换成其他形式或者提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
List list1=Arrays.asList("aaa","bbb");
list1.stream()
.map((str)->str.toUpperCase())
.forEach(System.out::println);
flatMap()-》接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流。
排序:
sorted()-》自然排序(Comparable)
List list2=Arrays.asList(1,2,5,9,4,6,7);
list2.stream()
.sorted()
.forEach(System.out::println);
sorted(Comparator com)-》定制排序
peek()
终止操作(终端操作)
查找与匹配:
min()-》返回流中的最小值
max()-》返回流中的最大值
count()-》返回流中元素的总个数
anyMatch()-》检查是否至少匹配一个元素
allMatch()-》检查是否匹配所有元素
noneMatch()-》检查时候没有匹配所有元素
findFirst()-》返回第一个元素
findAny()-》返回当前流中的任意一个元素
规约:
reduce()-》将流中元素反复结合起来得到一个值,把起始值作为x,然后从流中取出一个值作为y,然后以此类推。
List list2=Arrays.asList(1,2,5,9,4,6,7);
list2.stream()
.reduce(0,(x,y)->x+y);
收集:
collect()-》将流转换为其他形式。接收一个Collector接口的实现,用于给stream中元素做汇总的方法
list.stream()
.map(Person::getName)
.collect(Collectors.toList())
.forEach(System.out::println);
forEach()-》
forEachOrdered()
toArray()
Optional类
//不能传递null 否则出现空指针异常,在构建的时候 Optional
可以有默认方法(使用default关键字修饰,该方法可以实现),其中有一个是类优先原则,如果一个接口中定义了一个默认方法,另一个父类或接口中又定义了一个同名的方法时,选择父类中的方法,如果父类中提供了具体的实现,那么接口或接口中具有相同名称和参数的默认方法就会被忽略。接口冲突,如果一个父接口提供一个默认方法,另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认的),那么必须覆盖该方法来解决冲突。 静态方法:接口中可以有静态方法时间和日期的API
整体都在Time包下:是不可变的线程安全的。
java。time包中的是类是不可变且线程安全的。新的时间及日期API位于java.time中,下面是一些关键类
●Instant——它代表的是时间戳
//默认获取的是UTC(世界协调时间)时区为基础的 时间戳
Instant now = Instant.now();
System.out.println(now);
//进行偏移量运算,得到的为北京现在的时间
OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
//转换成毫秒
long l = now.toEpochMilli();
System.out.println(l);
●LocalDate——不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。
//今天的日期是:2021-03-16,只包含日期
LocalDate localDate=LocalDate.now();
System.out.println("今天的日期是:"+localDate);
//获取年月日
localDate.getYear();
localDate.getMonthValue();
localDate.getDayOfMonth();
●LocalTime——它代表的是不含日期的时间
//获取当前时间,不包含日期 当前的时间是:16:40:34.591
LocalTime localTime=LocalTime.now();
System.out.println("当前的时间是:"+localTime);
●LocalDateTime——它包含了日期及时间,不过还是没有偏移信息或者说时区。
//指定当前时间
LocalDateTime localDateTime=LocalDateTime.of(2021,10,10,10,10,10);
System.out.println(localDateTime);
//在当前的基础上加减年月日等;LocalDate只能加减年月日,LocalTime只能加减时分秒
LocalDateTime localDateTime1 = localDateTime.plusYears(1);
System.out.println(localDateTime1);
LocalDateTime localDateTime2 = localDateTime.minusYears(1);
System.out.println(localDateTime2);
●Duration:计算两个时间之间的间隔
●Period:计算两个日期之间的间隔
时间校正器:
TemporalAdjuster:
dayOfWeekInMonth() – 一周中的某一天,例如,三月中第二个星期二
firstDayOfMonth() – 当前月的第一天
firstDayOfNextMonth() – 下一个月的第一天
firstDayOfNextYear() – 下一年的第一天
firstDayOfYear() – 当年的第一天
lastDayOfMonth() – 当月的最后一天
nextOrSame() – 下一次或当天发生的一周中的某天
//指定为月中的第一天
LocalDateTime localDateTime2 = localDateTime.with(TemporalAdjusters.firstDayOfMonth());
System.out.println(localDateTime2);
可以自定义指定,查文档
时间日期格式化:DateTimeFormatter
DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_LOCAL_DATE;
LocalDateTime localDateTime3=LocalDateTime.now();
String format = localDateTime3.format(isoDateTime);
System.out.println(format);
DateTimeFormatter.ofPattern("自定义格式");
//将字符串解析成时间格式
LocalDateTime parse = localDateTime3.parse("需要解析的字符串", "格式");
时区的处理:
●ZonedTime
●ZonedDate
●ZonedDateTime——这是一个包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
Java9新特性
模块化特性
简单说模块是代码和数据的封装体。这里的代码指的是一些包含类型的Packages 。Packages是类路径名称,模块就是一个或者多个Package组成的封装体。
实现目标:
主要目的是在于减小内存的开销
只须必要模块,而非全部jdk模块,可以简化各种类库和大型应用的开发和维护
改进JavaSE平台,使其可以适应不同大小的计算设备
改进其安全性,可维护性,提高性能
如图所示,如果在ModuleTest中直接调用Person是不能调用的,因为处在不同的模块中。可以通过导入导出模块的方式进行调用。创建module-info.java文件。
被调用的:
module java9demo {
//导出包
exports com.hqm.pojo;
}
调用的:
module javatest {
//导入模块名
requires java9demo;
}
jShell命令
JShell其实就是一个命令行工具,输入片段代码马上就可以看到结果,相当于脚本一行行解析执行,用户可以体验一把Java交互式编程环境。
JShell的目标是提供一个交互工具,通过它来运行和计算java中的表达式。开发者可以轻松地与JShell交互,其中包括:编辑历史,tab键代码补全,自动添加分号,可配置的imports和definitions。其他的很多主流编程语言如python都已经提供了console,便于编写一些简单的代码用于测试。值得一提的是,JShell并不是提供了新的一个交互语言,在JShell中编写的所有代码都必须符合java语言规范;图形界面和调试支持也没有,JShell的一个目标是可以在IDE中使用JShell交互,而不是实现IDE实现的功能。
使用jShell,可以在命令行中输入jshell,就可以进入jshell环境。
默认情况下导入的包
多版本兼容jar包
多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本。接口的私有方法
jdk7只能定义抽象方法;jdk8可以定义默认方法和静态方法;jdk9可以定义私有方法
jdk9:
public interface MyInterface {
//定义默认方法
default void method1(){
System.out.println("接口中的私有方法");
method2();
}
//定义私有方法
private void method2(){
System.out.println("接口中的私有方法2");
}
}
钻石操作符(泛型)
在Java7之前每次声明泛型变量的时必须左右两边都同时声明泛型:
List list = new ArrayList();
在Java8中,对这一点进行了改进,就不必两边都要声明泛型,这种只适用<>标记的操作,称之为钻石操作符Diamond Operator:
List list = new ArrayList<>(); 类型推断
在Java9中,钻石操作符能与匿名实现类共同使用:
List list = new ArrayList<>() {
@Override
public int size() {
return super.size();
}
};
异常处理
JDK8异常处理对象必须在try的小括号内进行初始化。
JDK9新特性:
-try前边可以定义流对象
-try后边的( )中可以直接引入流对象的名称(变量名),此时的对象是final的。
-在try代码执行完毕后会自动释放资源,不用写finally
public static void main(String[] args) throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream("d:\a.txt");
FileOutputStream outputStream = new FileOutputStream("d:\d.txt");
try (inputStream; outputStream) { //引用多个的时候可以用分号分开
int len = 0;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
}catch (IOException e) {
e.printStackTrace();
}
}
下划线使用的限制
命名标识符的时候进行限制:
在java 8 中,标识符可以独立使用“_”来命名:
String _="hello"; 这样是可以的
在java 9 中规定“_”不再可以单独命名标识符了,如果使用,会报错:
String _="hello"; 这样是不行的
String底层存储结构的变化
之前存储string的结构是字符数组。jdk9中使用的存储结构是字节数组。如果是中文的话就会使用编码标识标注一下,UTF-16明确一个字符是两个字节。StringBuffer和StringBuild同样使用了字节数组。 public final class String implements java.io.Serializable, Comparable创建只读集合, CharSequence { @Stable private final byte[] value; ...... String:不可变的字符序列 StringBuffer:线程安全的,执行效率低,可变的字符序列 StringBuild:线程不安全的,执行效率高,可变的字符序列
jdk8集合变为只读:
List s=new ArrayList<>();
List s1=Collections.unmodifiableList(s);
jdk9集合变为只读:
List list = List.of(1, 2, 3); //调用of方法
//map中是entry类型的数组,map集合除了可以使用of方法,还可以使用ofEntries方法。
Map.ofEntries(Map.entry(1,2), Map.entry(3,4));
增强的StreamAPI
//jdk9中Stream新添加的四个方法
takeWhile::从 Stream 中获取一部分数据, 返回从头开始的尽可能多的元素,
//直到遇到第一个false结果,如果第一个值不满足断言条件,将返回一个空的 Stream
List list= Arrays.asList(1,3,5,2,4,6);
list.stream()
.takeWhile(x->x<4)
.forEach(System.out::println);
结果为:1,3
dropWhile:与 takeWhile相反,返回剩余的元素,和takeWhile方法形成互补
List list1= Arrays.asList(1,3,5,2,4,6);
list1.stream()
.dropWhile(x->x<4)
.forEach(System.out::println);
结果为:5,2,4,6
ofNullable:此方法返回一个包含单个元素的顺序Stream。如果提供的元素为null,则此方法返回空Stream。
//如果提供多个元素其中有null是没问题的
Stream.of(1,2,3,null)
.forEach(System.out::println);
//jdk8中单个元素的时候不允许为null,jdk9中可以存放单个为null的元素
Stream.of(null)
.forEach(System.out::println);
iterate:jdk8中的用法
Stream.iterate(0,x->x+1)
.limit(10) //进行限制输出
.forEach(System.out::println);
jdk9中可以有方法终止迭代
Stream.iterate(0,x->x<10,x->x+1)
.forEach(System.out::println);
Optional中增加Stream
List全新的HTTP客户端APIlist2 = new ArrayList<>(); list2.add("1"); list2.add("2"); list2.add("3"); list2.add("4"); Optional.ofNullable(list2) .stream() //新添加的stream方法 .forEach(System.out::println);
HttpClient是一个对多个请求配置了公共信息的容器。所有的请求通过一个HttpClient进行发送。HttpClients是不可变的,通过HttpClient的newBuilder()创建返回。请求Builders被HttpRequest#newBuilder()来创建。



