Java8新特性
Java8新特性
Java8新特性
1. Lambda表达式:称为闭包 lambda可把函数作为方法的参数进行传递 可访问外部作用域的变量
2. 方法引用: ‘::’双冒号 直接引用java类或特定对象的方法或构造器
3. 默认方法: 一个在接口里有可以有自己实现的默认方法(static或defaul修饰的)
4. 函数式接口:可作为参数列表处理
5. stream流api: java.util.stream 函数式编程
6. 日期和时间的增强api:加强对日期与时间处理
7. optional类:解决空指针等问题
8. js引擎:nashorn js引擎实现jvm上可运行js应用
Lambda表达式
Lambda表达式是JDK8的一个语法糖 简化匿名内部类写法 基本语法(参数列表)->{业务代码} 且参数类型明确时类型可省略 方法只存在一个参数时小括号可省略
PS: 方法引用:双冒号(::)
基础语法: ClassName::methodName (ClassName为包含静态(实例|对象)方法methodName的类名)
用处: 根据上下文推断参数类型 简化Lambda表达式语法结构
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
class Java8NewFeature{
public static void main(String[] args) throws InterruptedException {
// Lambda表达式
// 1. 常规
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("lambda示例");
}
}).start();
new Thread(()-> System.out.println("lambda示例")).start();
Thread.sleep(1000);
// 2. 方法引用
List<String> fruits = Arrays.asList("orange", "apple", "banana");
// fruits.sort((a, b) -> a.compareToIgnoreCase(b)); // Lambda表达式
// System.out.println(fruits);
fruits.sort(String::compareToIgnoreCase); // 方法引用
System.out.println("方法引用:" + fruits);
// 3. 集合遍历
//fruits.forEach(f-> System.out.println(f)); 等价于下面的操作
System.out.println("遍历场景");
fruits.forEach(System.out::println);
// 4. 排序
//fruits.sort((a, b) -> a.compareToIgnoreCase(b));
fruits.sort(String::compareToIgnoreCase);
System.out.println("排序场景:" + fruits);
// 5. 过滤
List<String> fs = fruits.stream().filter(f->f.startsWith("a")).collect(Collectors.toList());
System.out.println("过滤场景:" + fs);
// 6. 数据映射
List<Integer> lengths = fruits.stream().map(String::length).collect(Collectors.toList());
System.out.println("数据映射场景:"+ lengths);
// 7. 数据计算
List<Integer> list = Arrays.asList(5, 2, 1, 3, 4);
//Integer sum = list.stream().reduce(0, (a, b)->a+b);
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println("计算场景:" + sum);
// 8. 数据分组
Map<Integer, List<String>> group = fruits.stream().collect(Collectors.groupingBy(f->f.length()));
//Map<Integer, List<String>> group = fruits.stream().collect(Collectors.groupingBy(String::length));
System.out.println("数据分组:" + group);
// 9. 结合Optional操作
System.out.println("结合Optional");
Optional<String> ol = Optional.ofNullable("optional");
ol.map(String::toUpperCase).ifPresent(System.out::println);
// 10.结合stream
List<String> fss = fruits.stream().filter(f->f.startsWith("a")).map(String::toUpperCase).sorted().collect(Collectors.toList());
System.out.println("结合stream:"+ fss);
}
}
lambda示例
lambda示例
方法引用:[apple, banana, orange]
遍历场景
apple
banana
orange
排序场景:[apple, banana, orange]
过滤场景:[apple]
数据映射场景:[5, 6, 6]
计算场景:15
数据分组:{5=[apple], 6=[banana, orange]}
结合Optional
OPTIONAL
结合stream:[APPLE]
方法引用
@Slf4j
class Java8NewFeature{
class CalUtil{
// 构造方法引用
public static CalUtil init(final Supplier<CalUtil> supplier){
return supplier.get();
}
// 静态方法引用
public static int add(Integer n){
return n*n;
}
// 实例方法引用
public void instanceMethod(final CalUtil calUtil) {
System.out.println("实例方法引用");
}
// 任意对象方法引用
public void randomMethod(){
System.out.println("该类任意对象方法引用");
}
}
public static void main(String[] args) throws InterruptedException {
// 1. 构造方法引用className::new
Supplier<List<String>> supplier = ArrayList::new;
List<String> list = supplier.get();
boolean flag = list instanceof ArrayList;
System.out.println("构造方法引用:" + flag);
CalUtil newInstance = CalUtil.init(CalUtil::new);
System.out.println("构造方法引用:" + newInstance);
// 2. 静态方法引用className::staticMethodName
List<Integer> li = Arrays.asList(1, 3, 5, 7);
int sum = li.stream().mapToInt(CalUtil::add).sum();
System.out.println("静态方法引用:" + sum);
// 3.实例方法引用instance::methodName
List<CalUtil> cl = Collections.singletonList(newInstance);
cl.forEach(newInstance::instanceMethod);
// 4. (该类任意)对象方法引用className:methodName
cl.forEach(CalUtil::randomMethod);
}
}
构造方法引用:true
构造方法引用:CalUtil@7a0ac6e3
静态方法引用:84
实例方法引用
该类任意对象方法引用
Stream流
stream流通过顺序式stream()和并发式parallelStream()方法生成流,集合中的元素可以在stream流中通过内部迭代(类似iterator和for-each)和中间操作(进行过滤、排序、聚合等操作)完成预处理。
@Slf4j
class Java8NewFeature{
public static void main(String[] args) throws InterruptedException {
// stream流
// 1. filter:条件过滤元素
List<String> projectLi = Arrays.asList("chinese", "english", "math");
System.out.println("filter:" + projectLi.stream().filter(p -> p.length() > 4).collect(Collectors.toList()));
// 2. map:元素映射处理、转换成新值
System.out.println("map:" + projectLi.stream().map(String::toUpperCase).collect(Collectors.toList()));
// 3. forEach:遍历各元素执行额外业务处理
System.out.println("forEach:");
projectLi.forEach(p-> System.out.println(p.substring(1,3)));
// 4. flatMap:将流中元素转换为一个流,再将这些流合并为一个流
List<List<String>> strs = Arrays.asList(
Arrays.asList("a", "b", "c"),
Arrays.asList("A", "B", "C")
);
System.out.println("flatMap:" + strs.stream().flatMap(List::stream).collect(Collectors.toList()));
// 5. reduce:将流中元素进行累计操作
List<Integer> nums = Arrays.asList(300, 100, 200, 200);
System.out.println("reduce:" + nums.stream().reduce(0, Integer::sum));
System.out.println("reduce:" + nums.stream().reduce(0, Integer::max));
System.out.println("reduce:" + nums.stream().reduce(100, Integer::min));
System.out.println("reduce:" + nums.stream().reduce(1, (a,b)-> a*b));
// 6. distinct:将流中相同元素去重
System.out.println("distinct:" + nums.stream().distinct().collect(Collectors.toList()));
// 7. sorted:将流中元素进行排序
System.out.println("sort:" + nums.stream().sorted().collect(Collectors.toList()));
System.out.println("sort:" + nums.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList()));
// 8. limit:将流中元素进行限制返回个数
System.out.println("limit:" + nums.stream().limit(2).collect(Collectors.toList()));
// 9. skip:跳过指定数量的元素并返回剩余的元素
System.out.println("skip:" + nums.stream().skip(1).collect(Collectors.toList())); // 新list
System.out.println("skip+limit:" + nums.stream().skip(1).limit(1).collect(Collectors.toList()));
// 10. anyMatch(任意一个元素);allMatch(所有元素);noneMatch: 判断流中元素是否存在满足条件的元素 返回boolean
System.out.println("anyMatch:" + nums.stream().anyMatch(n->n == 200)); // boolean
System.out.println("allMatch:" + nums.stream().anyMatch(n->n == 200));
System.out.println("noneMatch:"+ nums.stream().anyMatch(n->n == 200));
// 11. findFirst(获取第一个)、findAny(获取任意一个): 从流中获取第一个或任意一个元素
System.out.println("findFirst:" + nums.stream().findFirst().orElse(null)); // optional对象
System.out.println("findAny:" + nums.stream().findAny().orElse(null));
// 12. min、max: 获取流中最小、最大值
System.out.println("min:" + nums.stream().min(Integer::compareTo).orElse(null)); // optional
System.out.println("max:" + nums.stream().max(Integer::compareTo).orElse(null)); // optional
// 13. groupingBy: 将流中元素按照条件分组
System.out.println("groupBy:" + nums.stream().collect(Collectors.groupingBy(n->n>0)));
// 14. partitioningBy: 将流中元素按照条件分成2个部分
System.out.println("partitioningBy:" + projectLi.stream().collect(Collectors.partitioningBy(n->n.length()>2)));
// 15. stream(常规顺序执行流)以及parallelStream(并行执行流 提升效率)
List<String> sl = Arrays.asList("s", "t", "r", "e", "a", "m");
System.out.println("parallelStream:" + sl.parallelStream().collect(Collectors.joining("")));
// 16. 统计-最大、最小、总和、平均值
List<Integer> cal = Arrays.asList(11, 15, 10, 9, 20, 6);
IntSummaryStatistics ss = cal.stream().mapToInt(n -> n).summaryStatistics();
System.out.println("cal-最大值:" + ss.getMax());
System.out.println("cal-最小值:" + ss.getMin());
System.out.println("cal-总和:" + ss.getSum());
System.out.println("cal-平均值:" + ss.getAverage());
}
)
filter:[chinese, english]
map:[CHINESE, ENGLISH, MATH]
forEach:
hi
ng
at
flatMap:[a, b, c, A, B, C]
reduce:800
reduce:300
reduce:100
reduce:1200000000
distinct:[300, 100, 200]
sort:[100, 200, 200, 300]
sort:[300, 200, 200, 100]
limit:[300, 100]
skip:[100, 200, 200]
skip+limit:[100]
anyMatch:true
allMatch:true
noneMatch:true
findFirst:300
findAny:300
min:100
max:300
groupBy:{true=[300, 100, 200, 200]}
partitioningBy:{false=[], true=[chinese, english, math]}
parallelStream:stream
cal-最大值:20
cal-最小值:6
cal-总和:71
cal-平均值:11.833333333333334
Optional类
Optional 类提供对应api是为了处理null即空指针问题 java.util.Optional<T> 不显式进行空值检测 而是通过对应api交给开发者做进一步处理
class Java8NewFeature{
public static void main(String[] args){
// Optional类
// 1. optional对象
Optional<Integer> empty = Optional.empty(); // 空optional对象( Optional<T> t = (Optional<T>) EMPTY;)
Optional<Integer> full = Optional.of(1); // 非空optional对象(不可未null 否则抛出异常) (new Optional<>(value);)
Optional<Integer> unKnown = Optional.ofNullable(null); // 可为空和非空的optional对象( return value == null ? empty() : of(value);)
System.out.println("optional-empty:" + empty);
System.out.println("optional-full:" + full);
System.out.println("optional-unKnown:" + unKnown);
//2. optional对象相关方法
System.out.println("empty.isPresent:" + empty.isPresent()); // 值是否为null
full.ifPresent(i-> System.out.println("full.ifPresent:" + i)); // 值不是null时的后续操作
System.out.println("full.get:" + full.get()); // 值不是null时的获取值 否则会抛出异常
System.out.println("unKnown.orElse:" + unKnown.orElse(2)); // 值为null时的默认的值
System.out.println("unKnown.orElseGet:" + unKnown.orElseGet(()->33)); // 值为null时的默认值(效果等同于orElse)
try {
full.orElseThrow(Exception::new);
}catch (Throwable e){
System.out.println("full.orElseThrow:值为null抛出异常");
}
try {
unKnown.orElseThrow(Exception::new);
}catch (Throwable e){
System.out.println("unKnown.orElseThrow:值为null抛出异常");
}
// 3. optional+map+filter使用
System.out.println("map+filter:" + unKnown.map(n->n+"a").filter(n-> n.startsWith("a")).orElse("nothing"));
}
}
optional-empty:Optional.empty
optional-full:Optional[1]
optional-unKnown:Optional.empty
empty.isPresent:false
full.ifPresent:1
full.get:1
unKnown.orElse:2
unKnown.orElseGet:33
unKnown.orElseThrow:值为null抛出异常
map+filter:nothing
接口的默认方法
接口的默认方法 即接口可以实现自己的方法(static或default修饰的方法) 不需要实现类后去实现方法 通过这种方式可以灵活解耦因版本迭代导致的接口变更问题
class Java8NewFeature{
interface DefaultInterface
{
default void getInfo()
{
System.out.println("我是接口的默认方法,我可以自己实现方法!");
}
static void staticMethod()
{
System.out.println("我是接口的静态方法,我可以自己实现方法!");
}
}
class DefaultInterfaceImpl implements DefaultInterface
{
public void getInfo()
{
DefaultInterface.super.getInfo();
System.out.println("我是接口的实现类,我重写了默认方法!");
}
public static void staticMethod()
{
DefaultInterface.staticMethod();
System.out.println("我是接口的实现类,我重写静态方法");
}
}
public static void main(String[] args)
{
new DefaultInterfaceImpl().getInfo();
DefaultInterfaceImpl.staticMethod();
}
}
我是接口的默认方法,我可以自己实现方法!
我是接口的实现类,我重写了默认方法!
我是接口的静态方法,我可以自己实现方法!
我是接口的实现类,我重写了静态方法!
函数式接口
函数式接口 使用@FunctionalInterface标识 只有一个抽象方法的接口 但可以有多个默认方法和静态方法 用来表示一个函数 函数的输入输出对应接口方法的参数列表和返回值 主要有Supplier Consumer Runnalbe Callable Function等类型 详见java.util.function
主要分类:
Supplier<T>: 无参数 返回一个结果 ()->T
Consumer<T>: 接收一个参数 无返回结果 (T)->void
Function<T,R>: 接收一个参数 返回一个结果 (T)->R
Predicate<T>: 接收一个参数 返回一个布尔值 (T)->boolean
UnaryOperator<T>: 接收一个参数 返回相同类型的结果 (T)->T
BinaryOperator<T>: 接收两个相同类型的参数 返回相同类型的结果 (T, T)->T
Runnable: 无参数 无返回值 ()->void
Callable<T>: 无参数 有返回值 可抛出异常 ()->T
应用场景:
并发编程:Runnable Callable接口实现创建线程任务处理
集合操作: 配合stream流对集合元素进行过滤 映射 排序等操作 接受函数式接口为参
函数组合: 通过Function接口可进行函数链式调用等操作
策略模式: 根据传递的不同函数式接口实现 动态变更其策略行为
日志记录: 自定义筛选条件进行日志记录等行为操作
@FunctionalInterface
interface MyPredicate<T>
{
boolean test(T t);
}
class Common<T>
{
public static <T> List<T> myPredicate(List<T> list, MyPredicate<T> mp)
{
List<T> li = new ArrayList<>(list.size());
for (T t: list){
if (mp.test(t)){
li.add(t);
}
}
return li;
}
public static <T> List<T> sourcePredicate(List<T> list, Predicate<T> mp)
{
List<T> li = new ArrayList<>(list.size());
for (T t: list){
if (mp.test(t)){
li.add(t);
}
}
return li;
}
public static <T> void sourceConsumer(List<T> list, Consumer<T> cr)
{
List<T> li = new ArrayList<>(list.size());
for(T t: list){
cr.accept(t);
}
}
public static<T> List<T> sourceSupplier(Supplier<T> sr)
{
List<T> li = new ArrayList<>();
for(int n=0;n<5;n++){
T t = sr.get();
li.add(t);
}
return li;
}
public static<T> Integer sourceFunction(List<T> li, Function<T, Integer> fn)
{
Integer count = 0;
for (T t: li){
Integer apply = fn.apply(t);
count += apply;
}
return count;
}
}
class Java8NewFeature{
public static void main(String[] args){
// packageName: java.util.function
// 1. Predicate<T>:(T)->boolean
List<Integer> nl = Arrays.asList(5, 7, 3);
System.out.println("Predicate:" + Common.myPredicate(nl, n->n>6));
Predicate<Integer> predicate = n->n>6;
System.out.println("Predicate:" + Common.sourcePredicate(nl, predicate));
// 2. Consumer<T>:(T)->void
Consumer sout = n->System.out.println("Consumer:" + n);
Common.sourceConsumer(nl, sout);
// 3. Supplier<T>:()->T
Supplier<Integer> supplier = ()-> new Random().nextInt(10);
System.out.println("Supplier:"+ Common.sourceSupplier(supplier));
// 4. Function<T,R>:(T)->R
Function<Integer, Integer> fn = n->n*2;
System.out.println("Function:" + Common.sourceFunction(nl, fn));
}
}
Predicate:[7]
Predicate:[7]
Consumer:5
Consumer:7
Consumer:3
Supplier:[7, 7, 3, 6, 8]
Function:30
js引擎
引入nashorn js引擎保证可运行js业务代码
命令行通过: jjs *.js
class Java8NewFeature{
public static void main(String[] args){
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("nashorn");
try{
// engine.eval(new FileReader("a.js")); // 执行js脚本文件
engine.eval("print('hello js');"); // 常规无参执行js
engine.eval("print('" + "自定义变量" +"')"); // 常规有参执行js
SimpleBindings sbs = new SimpleBindings(); // 全局变量传递
String globalVal = "全局变量";
sbs.put("globalVal", globalVal);
engine.eval("print(globalVal)", sbs);
String jsScript = "function cal(a,b){return a+b;}"; // 函数传参
engine.eval(jsScript);
Invocable invocable = (Invocable) engine;
Object cal = invocable.invokeFunction("cal", 1, 11);
System.out.println("js执行成功:" + cal);
}catch (ScriptException | NoSuchMethodException e){
System.out.println("js执行异常");
}
}
}
hello js
自定义变量
全局变量
js执行成功:12.0
日期时间增强api
增强的日期时间处理api 简化了日期时间处理 可通过Zoned自定义时区 同时也是线程安全
class Java8NewFeature{
public static void main(String[] args){
// 日期时间
LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
System.out.println("当前日期时间:" + localDateTime);
System.out.println("当前日期:" + localDate);
System.out.println("当前时间:" + localTime);
System.out.println("获取年月日:" +
localDateTime.getYear() +
" " + localDateTime.getMonthValue() +
" " + localDateTime.getDayOfMonth());
System.out.println("获取年月日:" +
localDate.getYear() +
" " + localDate.getMonthValue() +
" " + localDate.getDayOfMonth());
System.out.println("日期解析:" + LocalDate.of(2024, 10, 24));
System.out.println("日期解析:" + LocalDate.parse("2024-10-24"));
System.out.println("时间解析:" + LocalTime.parse("10:10:10"));
System.out.println("时间解析:" + LocalTime.of(10, 10, 10));
System.out.println("1年前的日期:" + LocalDate.now().minus(1, ChronoUnit.YEARS));
System.out.println("1年后的日期:" + LocalDate.now().plus(1, ChronoUnit.YEARS));
System.out.println("1周前的日期时间:" + LocalDateTime.now().minus(1, ChronoUnit.WEEKS));
System.out.println("1周后的日期时间:" + LocalDateTime.now().plus(1, ChronoUnit.WEEKS));
System.out.println("1小时前的时间:" + LocalTime.now().minusHours(1));
System.out.println("1小时后的时间:" + LocalTime.now().plusHours(1));
// System.out.println("1分钟后的时间:" + LocalTime.now().plusMinutes(1));
System.out.println("1分钟后的时间:" + LocalTime.now().plus(1, ChronoUnit.MINUTES));
System.out.println("1秒后的时间:" + LocalTime.now().plusSeconds(1));
// 时区
System.out.println("当前系统默认时区:" + ZoneId.systemDefault());
System.out.println("当前系统默认时区的日期时间:" + ZonedDateTime.now());
System.out.println("所有支持时区:" + ZoneId.getAvailableZoneIds().stream().count());
ZoneId zd = ZoneId.of("America/New_York");
System.out.println("纽约时区的日期时间:" + ZonedDateTime.now(zd));
System.out.println("纽约时区的日期时间:" + ZonedDateTime.now().withZoneSameInstant(zd));
System.out.println("当前UTC时间:" + Instant.now());
System.out.println("纽约时区的日期时间(UTC):" + Instant.now().atZone(zd));
}
}
当前日期时间:2024-10-28T17:26:47.281
当前日期:2024-10-28
当前时间:17:26:47.282
获取年月日:2024 10 28
获取年月日:2024 10 28
日期解析:2024-10-24
日期解析:2024-10-24
时间解析:10:10:10
时间解析:10:10:10
1年前的日期:2023-10-28
1年后的日期:2025-10-28
1周前的日期时间:2024-10-21T17:26:47.302
1周后的日期时间:2024-11-04T17:26:47.303
1小时前的时间:16:26:47.303
1小时后的时间:18:26:47.303
1分钟后的时间:17:27:47.303
1秒后的时间:17:26:48.303
当前系统默认时区:Asia/Shanghai
当前系统默认时区的日期时间:2024-10-28T17:26:47.304+08:00[Asia/Shanghai]
所有支持时区:600
纽约时区的日期时间:2024-10-28T05:26:47.312-04:00[America/New_York]
纽约时区的日期时间:2024-10-28T05:26:47.314-04:00[America/New_York]
当前UTC时间:2024-10-28T09:26:47.314Z
纽约时区的日期时间(UTC):2024-10-28T05:26:47.314-04:00[America/New_York]
参考文档
[1] https://www.baeldung.com/java-optional

浙公网安备 33010602011771号