Java8中的Interface接口
interface接口的设计目的是面向接口编程,提高扩展性。
·Java8 中,接门中除了抽象方法外,还可以定义 default 默认方法和 static 静态方法。
- default 修饰的默认方法,属于实例方法,可以被实现类调用或重写。0
调用: 实现类必须 implements 接口,才能调用该接口的 default 默认方法。
重写: 实现类 implements 不同接口时,接口中存在相同签名的方法(名称、参数、类型完全一致),则实现类必须重写该方法,明确方法定义;
·static 修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用 interface 接门名称调用。
lambda表达式
- Lambda表达式本质是一个匿名函数,用于把函数作为参数,传入方法中,实现函数式编程风格。
- 使用Lambda表达式可以使代码变得更加简洁紧凑
语法格式
(parameters)->expression 或 (parameters)->{statements;}
函数式接口Functional Interface
只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用@FunctionalInterface接口定义,强化语义规范。
函数式接口,也被称为SAM接口(Single Abstract Method Interface)
作用
基于函数式接口,可以使用Lambda表达式进行实现,实现函数式编程。
示例
示例1:排序
函数式接口Comparaor
@FunctionalInterface
public interface Comparator<T>{
int compare(T o1,T o2);
}
使用Lambda实现函数式接口
//lambda表达式实现字符串数组排序
List<String> list = null;
list.sort((o1,o2)->{
if (o1.length() == o2.length()){
return o1.compareTo(o2);
}
return o1.length() - o2.length();
});
System.out.println(list);
示例2:迭代
使用Lambda迭代遍历集合
List<String> langList = Arrays.asList("Basic","QBaisc","c","c++","PowerBuilder");
//方式一
for(String lang : langList){
System.out.println(lang);
}
//方式二
langList.forEach((name)->{
System.out.println(name);
});
内置函数式接口(Build-in Functional Interfaces)
在Java8中专门有一个包放函数式接口java.util.function,该包下的所有接口都有@FunctionalInterface注解,提供函数式编程方式。
Predicate接口
Predicate 接口是只有一个参数的返回布尔类型值的断言型接口。该接口包含多种默认方法来将 Predicate组合成其他复杂的逻辑 (比如: 与 and ,或 or ,非 negate):
Predicate 断言型接口:
List<String> langList = Arrays.asList("Basic","QBaisc","c","c++","PowerBuilder","C#");
int len = 5;
Predicate<String> predicateLen = (str)->{
if(str.length() <= len){
return true;
}
return false;
};
//判断前缀
String prefix = "C";
Predicate<String> predicatefix = (str)->{
if(str.startsWith(prefix)){
return false;
}
return true;
};
//逻辑与
Predicate<String> conditionAnd = predicateLen.and(predicatefix);
//逻辑或
Predicate<String> conditionOr = predicateLen.or(predicatefix);
//逻辑非
Predicate<String> conditionNot = predicateLen.negate();
//遍历判断
langList.forEach((name)->{
if (conditionAnd.test(name)){
System.out.println(name);
}
});
langList.stream() //换行成Stream流
.map((lang)->{ //map映射器
// return lang.toLowerCase();
return lang.length();
})
.forEach((lang)->{ //遍历
System.out.println(lang);
});
Function
Function接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose,andThen)。
List<String> langList = Arrays.asList("Basic","QBaisc","c","c++","PowerBuilder","C#");
//功能1:抓换成小写形式
Function<String,String> fun1 = (lang)->{
System.out.println("fun1");
return lang.toLowerCase();
};
//功能2:添加括号
Function<String,String> fun2 = (lang) ->{
System.out.println("fun2");
return String.format("<%s>",lang);
};
//组合
Function<String,String> fun3 = fun1.andThen(fun2);
Function<String,String> fun4 = fun1.compose(fun2);
langList.stream()
.map(fun3) //映射操作
.forEach((lang)->{ //遍历
System.out.println(lang);
});
Comparator
比较器接口,用于比较指定元素值的大小。Java 8版本中,添加了多个新的default方法,用于比较器合并、反转等操作。
List<String> langList = Arrays.asList("Basic","QBaisc","c","c++","PowerBuilder","C#");
//两种比较规则
//比较规则1:按照内容ASCII比较
Comparator<String> comp1 = (x,y)->{
return x.compareTo(y);
};
//比较规则2:按照长度
Comparator<String> comp2 = (x,y)->{
return x.length() - y.length();
};
//比较规则3:先比较内容,再比较长度
Comparator<String> comp3 = comp1.thenComparing(comp2);
//比较规则4:按照内容的降序
Comparator<String> comp4 = comp1.reversed();
//排序
langList.sort(comp4);
System.out.println(langList);
Stream流
- java.util.Stream表示能应用在一组元素上一次执行的操作序列
- Stream操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,可以联系完成多个操作。
创建Stream
Stream的创建需要指定一个数据源。
//集合 ->Stream
List<String> list = Arrays.asList("稻香","七里香","东风破","青花瓷");
//数组 -> Stream
String[] array = {"稻香","七里香","东风破","青花瓷"};
Stream<String> arrayStream = list.stream();
常用方法
Filter过滤
过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作数据中间操作。所以过滤后的结果,可以继续进行其它Stream操作(例如forEach,forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作)。
String[] array = {"稻香","七里香","东风破","青花瓷","稻香","七里香","爱如潮水"};
long count = Arrays.stream(array).filter((music)->{
return music.length() == 3;}) //先过滤
.count();
System.out.println(count);
Sorted排序
排序是一个中间操作,返回的是排序好后的Stream。(不影响原数据)
//串行流
long count = values.stream().sorted().count();
//并行流
// long count = values.parallelStream().sorted().count();
Map映射
映射是一个中间操作,会将元素根据指定的Function接口来依次将元素转成另外的对象。
Match匹配
Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。
//是否存在一个名称长度为两个字的歌曲
boolean isContains1 = list.stream().anyMatch((music)->{return music.length() == 2;});
System.out.println(isContains1);
//所有歌曲全部都符合长度为2
boolean isContains2 = list.stream().allMatch((music)->{return music.length() == 2;});
System.out.println(isContains2);
//所有歌曲全部都不符合长度为1
boolean isContains3 = list.stream().noneMatch((music)->{return music.length() == 1;});
System.out.println(isContains3);
Count技术
计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。
String[] array = {"稻香","七里香","东风破","青花瓷","稻香","七里香","爱如潮水"};
long count = Arrays.stream(array).filter((music)->{
return music.length() == 3;}) //先过滤
.count();
System.out.println(count);
Collect收集
收集是一个最终操作,返回Stream中元素集合,返回值类型是集合(List、Set、Map)或字符串。
将Stream中的元素,收集至新集合
- Collectors.toList()
- Collectors.toSet()
- Collectors.toMap()
String[] array = {"稻香", "七里香", "东风破", "青花瓷", "稻香", "七里香", "爱如潮水"};
//distinct去重后,Stream中的元素收集成一个List
List<String> musicList = Arrays.stream(array).distinct().collect(Collectors.toList());
System.out.println(musicList);
//Stream中的元素收集成一个Set集合
Set<String> musicSet = Arrays.stream(array).collect(Collectors.toSet());
System.out.println(musicSet);
//distinct去重后,Stream中的元素收集成一个LinkedList
LinkedList<String> musicLinkedList =
Arrays.stream(array).distinct().collect(Collectors.toCollection(LinkedList::new));
System.out.println(musicLinkedList);
//Stream中的元素收集成一个LinkedHashSet集合
LinkedHashSet<String> musicLinkedSet =
Arrays.stream(array).collect(Collectors.toCollection(LinkedHashSet::new));
System.out.println(musicLinkedSet);
String[] array = {"稻香", "七里香", "东风破", "青花瓷", "稻香", "七里香", "爱如潮水"};
Stream<String> stream = Arrays.stream(array);
//将Stream流中的元素收集为一个Map集合
Map<String,Integer> resultMap1 = stream.distinct().collect(
Collectors.toMap(
(music)->{return music;},
(music)->{return music.length();}));
System.out.println(resultMap1);
Map<String,Integer> resultMap2 = stream.distinct()
.collect(
Collectors.toMap(
music->music,
music->music.length()));
System.out.println(resultMap2);
- Collectors.mapping() 将Stream中的元素,映射后,收集至新集合
List<String> strlist = Arrays.asList("12","23","34","45","56","67");
//收集元素的同时,进行mapping映射操作
List<Integer> numList = strlist.stream().collect(
Collectors.mapping(
s->Integer.parseInt(s)*10,
Collectors.toList()));
System.out.println(strlist);
System.out.println(numList);
- Collectors.groupingBy() 将Stream中的元素,分组后,收集至Map集合
- Collectors.partitioningBy() 将Stream中的元素,按照判断规则,统计分区后,收集至Map集合
List<String> nameList = Arrays.asList("曹操","曹丕","菠萝吹雪","张良","张忠","夏侯惇","夏侯","曹植");
Map<Character,List<String>> resultMap = nameList.stream().collect(
Collectors.groupingBy(
name->name.charAt(0)));
System.out.println(resultMap);
Map<Boolean,List<String>> resultPartingMap = nameList.stream()
.collect(Collectors.partitioningBy(
name->name.length()==2));
System.out.println(resultPartingMap);
Statistics统计
统计是一个最终操作,返回Stream中元素的各类统计信息,返回值类型是XXXConsumer。
List<Integer> number = Arrays.asList(1,2,4,5);
//List->Stream
Stream<Integer> stream = number.stream();
//Stream -> IntStream
IntStream intStream = stream.mapToInt(x->x);
//统计结果对象
IntSummaryStatistics statistics = intStream.summaryStatistics();
System.out.println("最大值:"+statistics.getMax());
System.out.println("最小值:"+statistics.getMin());
System.out.println("平均值:"+statistics.getAverage());
System.out.println("累加和:"+statistics.getSum());
Parallel Streams并行流
Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0;i<max;i++){
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
long start = System.currentTimeMillis();
//串行流
long count = values.stream().sorted().count();
//并行流
// long count = values.parallelStream().sorted().count();
long end = System.currentTimeMillis();
System.out.println(end-start);
函数式接口总结
- Predicate、Function、Consumer、Comparator
- 通过链式编程,使得它可以方便地对数据进行链式处理
- 方法参数都是函数式接口类型
- 一个Stream只能操作一次,操作完就关闭了,继续使用这个Stream会报错
- Stream不保存数据,不改变数据源
日期时间
Java 8 在java.time包下包含一个全新的日期和时间API
- LocalDateTime //日期+时间 format:yyyy-MM-ddTHH:mm:ss.SSS
- LocalDate //日期 format:yyyy-MM-dd
- LocalTime //时间 format:HH:mm:ss
格式化
//获取当前时间和日期
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now().withMinute(0);
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(String.format("当前日期:%s",date));
System.out.println(String.format("当前时间:%s",time));
System.out.println(String.format("日期时间:%s",dateTime));
System.out.println();
字符串日期格式
//类型转换
//字符串 ->LoaclDate
String strDate = "2023-08-19";
date = LocalDate.parse(strDate);
System.out.println(String.format("指定日期:%s",date));
//整数值->LocalDate
date = LocalDate.of(2023,8,19);
System.out.println(String.format("指定日期:%s",date));
//LoaclDate -> 字符串
日期计算
LocalDate date = LocalDate.now();
LocalDate after = date.plus(1, ChronoUnit.WEEKS);
System.out.println("一周后日期:"+after);
LocalDate before = date.plus(-1, ChronoUnit.WEEKS);
System.out.println("一周前日期:"+before);
//计算两个日期间隔多少天,多少年,多少月
LocalDate date1 = LocalDate.parse("2001-10-05");
LocalDate date2 = LocalDate.parse("2023-10-05");
Period result = Period.between(date1,date2);
System.out.printf("间隔%d年,%d月,%d日",result.getYears(),result.getMonths(),result.getDays());
//计算两个日期间隔:多少天
long days = date1.toEpochDay() - date2.toEpochDay();
System.out.println("间隔"+days+"天");
获取指定日期
//当前日期
LocalDate today = LocalDate.now();
//获取当前月第一天
LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("当前月第一天:"+firstDayOfMonth);
// 获取当前月最后一天
System.out.println("本月最后一天:"+today.with(TemporalAdjusters.lastDayOfMonth()));
//下个月第一天
System.out.println(today.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1));
//本月的最后一个星期一
System.out.println(today.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)));