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

[2]https://www.runoob.com/java/java8-new-features.html

[3]https://blog.csdn.net/wswpomos/article/details/143091682

posted @ 2024-10-28 17:30  爱编程_喵  阅读(32)  评论(0)    收藏  举报
jQuery火箭图标返回顶部代码

jQuery火箭图标返回顶部代码

滚动滑动条后,查看右下角查看效果。很炫哦!!

适用浏览器:IE8、360、FireFox、Chrome、Safari、Opera、傲游、搜狗、世界之窗.