1、JDK8之default关键字
可以在接口中添加实现方法。
场景:实现类所共有的一些逻辑代码,可以写到接口方法中。
default修饰的方式,可以被实现类重写。调用方式:实现类.default方式
static修饰的方法,不可以被实现类重写。调用方式:接口.静态方法
public interface Vegetables {
void onName();
default void onUnify(){
System.out.println("我是蔬菜");
}
static void onStaticUnify(){
System.out.println("我是静态蔬菜");
}
}
public class VegetablesImpl implements Vegetables {
@Override
public void onName() {
System.out.println("蔬菜实现类");
}
/** 可以重写default修饰的方法*/
}
public class Jdk8 {
public static void main(String[] args) {
Vegetables vegetables = new VegetablesImpl();
vegetables.onName();
vegetables.onUnify();
Vegetables.onStaticUnify();
}
}
2、JDK8新增Base64加解密API
不用引包,编解码效率高于sun.misc和Apache Commons Codec
public static void main(String[] args) throws Exception{
String str = "相信自己";
Base64.Encoder encoder = Base64.getEncoder();
Base64.Decoder decoder = Base64.getDecoder();
String encodeToString = encoder.encodeToString(str.getBytes("utf-8"));
System.out.println("加密后的字符串 "+encodeToString);
String decoderStr = new String(decoder.decode(encodeToString), "utf-8");
System.out.println("解密后的字符串 "+decoderStr);
}
3、JDK8新增日期时间API
从Java 8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:
本地日期和时间:LocalDateTime,LocalDate,LocalTime;
带时区的日期和时间:ZonedDateTime;
时刻:Instant;
时区:ZoneId,ZoneOffset;
时间间隔:Duration。
以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter。
此外,新API修正了旧API不合理的常量设计:
Month的范围用1~12表示1月到12月;
Week的范围用1~7表示周一到周日。
public class Main {
public static void main(String[] args) {
LocalDate d = LocalDate.now(); // 当前日期
LocalTime t = LocalTime.now(); // 当前时间
LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
System.out.println(d); // 严格按照ISO 8601格式打印
System.out.println(t); // 严格按照ISO 8601格式打印
System.out.println(dt); // 严格按照ISO 8601格式打印
}
}
LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
LocalDate d = dt.toLocalDate(); // 转换到当前日期
LocalTime t = dt.toLocalTime(); // 转换到当前时间
通过指定的日期和时间创建LocalDateTime可以通过of()方法:
// 指定日期和时间:
LocalDate d2 = LocalDate.of(2019, 11, 30); // 2019-11-30, 注意11=11月
LocalTime t2 = LocalTime.of(15, 16, 17); // 15:16:17
LocalDateTime dt2 = LocalDateTime.of(2019, 11, 30, 15, 16, 17);
LocalDateTime dt3 = LocalDateTime.of(d2, t2);
将字符串转换为LocalDateTime就可以传入标准格式
LocalDateTime dt = LocalDateTime.parse("2019-11-19T15:16:17");
LocalDate d = LocalDate.parse("2019-11-19");
LocalTime t = LocalTime.parse("15:16:17");
注意ISO 8601规定的日期和时间分隔符是T。标准格式如下:
日期:yyyy-MM-dd
时间:HH:mm:ss
带毫秒的时间:HH:mm:ss.SSS
日期和时间:yyyy-MM-dd'T'HH:mm:ss
带毫秒的日期和时间:yyyy-MM-dd'T'HH:mm:ss.SSS
DateTimeFormatter:自定义输出的格式。
public class Main {
public static void main(String[] args) {
// 自定义格式化:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(dtf.format(LocalDateTime.now()));
// 用自定义格式解析:
LocalDateTime dt2 = LocalDateTime.parse("2019-11-30 15:16:17", dtf);
System.out.println(dt2);
}
}
LocalDateTime提供了对日期和时间进行加减的非常简单的链式调用:
public class Main {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2019, 10, 26, 20, 30, 59);
System.out.println(dt);
// 加5天减3小时:
LocalDateTime dt2 = dt.plusDays(5).minusHours(3);
System.out.println(dt2); // 2019-10-31T17:30:59
// 减1月:
LocalDateTime dt3 = dt2.minusMonths(1);
System.out.println(dt3); // 2019-09-30T17:30:59
}
}
注意到月份加减会自动调整日期,例如从2019-10-31减去1个月得到的结果是2019-09-30,因为9月没有31日。
调整是替换------
对日期和时间进行调整则使用withXxx()方法,例如:withHour(15)会把10:11:12变为15:11:12:
调整年:withYear()
调整月:withMonth()
调整日:withDayOfMonth()
调整时:withHour()
调整分:withMinute()
调整秒:withSecond()
public class Main {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2019, 10, 26, 20, 30, 59);
System.out.println(dt);
// 日期变为31日:
LocalDateTime dt2 = dt.withDayOfMonth(31);
System.out.println(dt2); // 2019-10-31T20:30:59
// 月份变为9:
LocalDateTime dt3 = dt2.withMonth(9);
System.out.println(dt3); // 2019-09-30T20:30:59
}
}
同样注意到调整月份时,会相应地调整日期,即把2019-10-31的月份调整为9时,日期也自动变为30。
要判断两个LocalDateTime的先后,可以使用isBefore()、isAfter()方法,对于LocalDate和LocalTime类似:
public class Main {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime target = LocalDateTime.of(2019, 11, 19, 8, 15, 0);
System.out.println(now.isBefore(target));
System.out.println(LocalDate.now().isBefore(LocalDate.of(2019, 11, 19)));
System.out.println(LocalTime.now().isAfter(LocalTime.parse("08:15:00")));
}
}
LocalDateTime无法与时间戳进行转换,因为LocalDateTime没有时区,无法确定某一时刻。
--------------------------------------》52《----------------------------------------
ZonedDateTime:带时区的日期和时间。
public void tt(){
//默认当前计算机时区
ZonedDateTime now = ZonedDateTime.now();
//指定伦敦时区
ZonedDateTime london = ZonedDateTime.now(ZoneId.of("Europe/London"));
System.out.println(now);
System.out.println(london);
}
计算机存储的当前时间,本质上只是一个不断递增的整数。Java提供的System.currentTimeMillis()返回
的就是以毫秒表示的当前时间戳。
这个当前时间戳在java.time中以Instant类型表示,我们用Instant.now()获取当前时间戳,效果和
System.currentTimeMillis()类似:
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now.getEpochSecond()); // 秒
System.out.println(now.toEpochMilli()); // 毫秒
}
}
4、JDK8新增Optional类
Optional类用来解决对象空指针异常的问题的,提供针对空指针异常的操作的AIP。
Optional私有化构造方法,只能通过静态方法获取。
如果传入参数为空,将会抛出异常
Optional.of();
Integer integer = null;
Optional<Integer> optional = Optional.of(integer);
传入的参数可以为空,也可以不为空。但是get()方法获取时,如果为空抛出异常
Optional.ofNullable
Integer integer = null;
Optional<Integer> optional = Optional.ofNullable(integer);
Integer integer1 = optional.get();
System.out.println(integer1);
检测Optional是否为空,不为空可以通过get()方法,获取具体value
isPresent()
Integer integer = null;
Optional<Integer> optional = Optional.ofNullable(integer);
if(optional.isPresent()){
System.out.println("不为空"+optional.get());
}else{
System.out.println("为空");
}
如果Optional不为空,则返回Optional值,如果Optional为空,则返回orElse传入的参数
orElse()
Integer integer = null;
Integer integer1 = new Integer(22);
Integer integer2 = Optional.ofNullable(integer).orElse(integer1);
System.out.println(integer2); //2
5、JDK8新增Lambda表达式
函数式编程
JDK1.8之前不支持函数式编程,1.8以后支持。
函数式编程,是将一个函数(或称为方法)作为一个参数进行传递。
lambda表达式
注意:一个接口中只包含一个方法,则可以使用Lambda表达式,这样的接口成为"函数式接口"
声明该接口为函数式接口
@FunctionalInterface
public interface Belief {
void onShow();
}
public class Jdk8 {
public static void main(String[] args) throws Exception{
onBelief(()-> System.out.println("我相信"));
}
public static void onBelief(Belief belief){
belief.onShow();
}
}
(参数) -> {方法体}
注意:
(1)如果参数为空,直接写() 如果只有一个参数,可以省略(),不需要写参数的类型。
(2)如果方法体只有一句代码,可以省略{}、省略return、省略分号。
6、JDK8提供Function接口
Lambda表达式必须先定义接口,才能使用。所有JDK8内置了许多函数式接口。
Function<T,R> 函数型接口,T入参 R返回值 只支持T一个入参
R apply(T t);
public static void main(String[] args) throws Exception {
Function<String,String> function = str -> str;
String apply = function.apply("你好我叫张三");
System.out.println(apply);
}
7、JDK8提供BiFunction接口
@FunctionalInterface
public interface BiFunction<T, U, R> {}
R apply(T t, U u); 与Function相似 只不过可以接口2个参数
public static void main(String[] args) throws Exception {
BiFunction<String,String,StringBuffer> biFunction = (a,b) -> {
return new StringBuffer().append(a).append(b);
};
StringBuffer buffer = biFunction.apply("Hello", "World");
System.out.println(buffer.toString());
}
8、JDK8提供Consumer接口
Consumer 消费型接口 有入参 无返回值
void accept(T t);
使用场景:用于打印、发送短信等消费动作
public static void main(String[] args) throws Exception {
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("打印输出");
}
9、JDK8提供Supplier接口
Supplier 供给型接口 无入参 有返回值
T get();
用途:返回创建对象
public class Jdk8 {
public static void main(String[] args) throws Exception {
Supplier<List<String>> supplier = () -> {
return Arrays.asList("a", "b", "c");
};
List<String> list = supplier.get();
list.forEach(str -> System.out.println(str));
}
}
10、JDK8提供Predicate接口
Predicate 断言型接口 有入参 有返回值 但是返回是Boolean
boolean test(T t);
public static void main(String[] args) throws Exception {
Predicate<Integer> predicate = i -> i.intValue() == 1;
boolean b = predicate.test(2);
System.out.println(b);
}
11、JDK8新增方法与构造器引用
调用方式或构造器引用 使用 :: 完成,接收参数为函数式接口。
调用(类,实例对象) :: 方法名;
静态方法调用 Class::方法名;
实例方法调用 对象::方法名;
构造方法调用 Class::new;
public class Jdk8 {
public static void main(String[] args) throws Exception {
Function<String,Integer> function = Integer::parseInt;
Integer integer = function.apply("123");
System.out.println(integer);
Supplier<MyUser> supplier0 = () -> {
return new MyUser();
};
//等价于上面写法
Supplier<MyUser> supplier = MyUser::new;
MyUser myUser = supplier.get();
}
static class MyUser{
private String name;
public MyUser() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
12、JDK8新增Stream
stream 中文成为"流" 通常将集合转换为一种"流"元素队列,能够对集合中的每一个元素进行并行或串行的流
水线操作,可以进行排序、聚合、过滤等操作。
stream()串行流
parallelStream()并行流
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> collect = list.stream().map(o -> {
if (o % 2 == 0) {
o++;
}
return o;
}).collect(Collectors.toList());
System.out.println(collect);
13、Stream之Map函数
1.Map函数
Map接收Function<T,R>函数型接口,可以直接对流中的每一个元素就行操作。
案例:通过map函数过滤返回铭感信息
@Data
public class Order {
private String id;
//敏感信息
private String bankNum;
private String name;
}
@Data
public class OrderDTO {
private String id;
private String name;
}
public static void main(String[] args) throws Exception {
List<Order> orders = Arrays.asList(new Order("1", "2889898", "滑板"),
new Order("2", "23232898", "面包"));
List<Object> objects = orders.stream().map(obj -> {
OrderDTO orderDTO = new OrderDTO(obj.getId(), obj.getName());
return orderDTO;
}).collect(Collectors.toList());
System.out.println(objects);
}
14、Stream之filter函数
1.Filter函数
filter接收 Predicate 断言型接口,可以对数据进行过滤。
public static void main(String[] args) throws Exception {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
//只返回奇数
List<Integer> integers = list.stream().filter(o -> o % 2 != 0).collect(Collectors.toList());
System.out.println(integers);
}
15、Stream之limit函数
limit 截取返回指定数量
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> collect = list.stream().limit(3).collect(Collectors.toList());
System.out.println(collect);
16、Stream之sorted函数
sorted 排序 自定义排序 默认升序
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
//降序
List<Integer> collect1 = list.stream().sorted(Comparator.comparing(o ->
o,Comparator.reverseOrder())).collect(Collectors.toList());
System.out.println(collect1);
17、Stream之allMatch函数
allMatch函数
检查是否匹配所有元素,只有全部匹配才返回true
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
//判断集合中是否所有元素都大于2
boolean b = list.stream().allMatch(o -> o > 2);
System.out.println(b); //false
18、Stream之anyMatch函数
anyMatch函数
检查是否匹配任意一个元素,匹配返回true 否则false
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
//判断集合中任意一个元素是否大于2
boolean b = list.stream().anyMatch(o -> o > 2);
System.out.println(b); //true
19、Stream之Max函数
Max找出集合中最大值
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
/**
*
* Comparator 也属于函数式接口
* int compare(T o1, T o2);
*/
Optional<Integer> max = list.stream().max((x, y) -> {
return Integer.compare(x,y);
});
if(max.isPresent()){ System.out.println(max.get()); } //6
20、Stream之Min函数
min找出集合中最小值
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
/**
*
* Comparator 也属于函数式接口
* int compare(T o1, T o2);
*/
Optional<Integer> max = list.stream().min((x, y) -> {
return Integer.compare(x,y);
});
if(max.isPresent()){ System.out.println(max.get()); }
21、Stream之parallelStream
paralleStream用fork/join框架提供了并发执行能力。
底层原理:
线程池(ForkJoinPool)维护一个线程队列。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
list.parallelStream().forEach(x ->{
System.out.println("并发发送通知消息Id="+x);
});
paralleStream并行是否一定比Stream串行快?
不一定,数据量小的情况,可能Stream串行流更快,ForkJoin会消耗性能。
paralleStream多线程操作,会出现并发访问的问题。
22、Stream之reduce函数
reduce操作
聚合操作,根据一定的规则将stream中的元素进行计算后返回一个唯一的值。
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T>
Stream.of创建一个流
常用方法一
Optional<T> reduce(BinaryOperator accumulator);
Optional<Integer> optional = Stream.of(1, 2, 3, 4, 5).reduce((x, y) -> x + y);
if(optional.isPresent()){
System.out.println(optional.get()); //15
}
常用方法二
输入一个初始值 identity
T reduce(T identity,BinaryOperator accumulator);
Integer integer = Stream.of(1, 2, 3, 4, 5).reduce(100, (x, y) -> x + y);
System.out.println(integer); //115
23、foreach
forEach函数里面实现为
@FunctionalInterface
public interface Consumer<T> 消费型接口
Stream.of(1, 2, 3, 4, 5).forEach(System.out::println);
注意点:
使用forEach在消费型接口实现中,不能使用return、break、continue等关键跳过或者终止操作。
24、Collector
collect()
一个终端操作,用于对流中的数据进行归集作用,将流转变成具体的一个数据集合。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> list1 = list.stream().collect(Collectors.toList());
Set<Integer> set = list.stream().collect(Collectors.toSet());
LinkedHashSet<Integer> hashSet = list.stream().collect(Collectors.toCollection(LinkedHashSet::new));
TreeSet<Integer> treeSet = list.stream().collect(Collectors.toCollection(TreeSet::new));
Map<Integer, Integer> collect = list.stream().collect(Collectors.toMap(x -> x, x -> x));
25、joining函数
拼接函数 Collectors.joining
3种重载
Collectors.joining()
Collectors.joining("分隔符")
Collectors.joining("分隔符","头","尾")
String collect = Stream.of("张三", "李四", "王五", "马六").collect(Collectors.joining());
//张三李四王五马六
System.out.println(collect);
String collect1 = Stream.of("张三", "李四", "王五", "马六").collect(Collectors.joining("--"));
//张三--李四--王五--马六
System.out.println(collect1);
String collect2 = Stream.of("张三", "李四", "王五", "马六").collect(Collectors.joining("--", "开头", "结尾!"));
//开头张三--李四--王五--马六结尾!
System.out.println(collect2);
26、partitioningBy函数
Collectors.partitioningBy分区,key是Boolean类型。
符合条件分成一组,不符合条件分成一组。
List<Integer> list = Arrays.asList(20, 60, 78, 92, 59);
//将大于60分的分成一组 小于60分的分成一组
Map<Boolean, List<Integer>> collect = list.stream().collect(Collectors.partitioningBy(x -> x >= 60));
//{false=[20, 59], true=[60, 78, 92]}
System.out.println(collect);
27、groupingBy函数
Collectors.groupingBy() 分组
public static void main(String[] args) throws Exception {
List<Integer> list = Arrays.asList(20, 60,20, 78, 92, 59);
// 分组
Map<Integer, List<Integer>> collect = list.stream().collect(Collectors.groupingBy(x -> x));
//{20=[20, 20], 59=[59], 92=[92], 60=[60], 78=[78]}
System.out.println(collect);
}
public static void main(String[] args) throws Exception {
List<Integer> list = Arrays.asList(20, 60,20, 78, 92, 59);
// 分组 并统计个数
Map<Integer, Long> collect = list.stream().collect(Collectors.groupingBy(x -> x, Collectors.counting()));
//{20=2, 59=1, 92=1, 60=1, 78=1}
System.out.println(collect);
}
28、summarizing函数
Collectors.summarizing类型()用来处理数据的统计分析的,比如总合、平均数等等
public static void main(String[] args) throws Exception {
List<Integer> list = Arrays.asList(20, 60,20, 78, 92, 59);
IntSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingInt(x -> x));
System.out.println("平均数"+summaryStatistics.getAverage()); //System.out.println("平均数"+summaryStatistics.getAverage());
System.out.println("总数"+summaryStatistics.getCount()); //总数6
System.out.println("总合"+summaryStatistics.getSum()); //总合329
System.out.println("最大值"+summaryStatistics.getMax()); //最大值92
System.out.println("最小值"+summaryStatistics.getMin()); //最小值20
}