栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java8 新特性

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java8 新特性

目录
    • 函数式接口
    • Lambda表达式
    • 方法引用
    • 接口增强
    • Stream API
    • Optional类
    • 时间日期API
    • 可重复注解
    • Nashorn JavaScript引擎
    • Base64


函数式接口

函数式接口:有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。可以被隐式转换为lambda表达式。
Java8新增的函数式接口:

接口方法描述
Consumer< T >void accept(T t)消费型接口,对类型为T的对象应用操作
Supplier < T >T get()供给型接口,返回类型为T的对象
Function < T >R apply(T t)函数型接口,对类型为T的对象操作,返回类型为R的对象
Predicate < T >boolean test(T t)断定型接口,对类型为T的对象操作,返回boolean值

实例:

public class Test {
    public static void main(String args[]){
        predicate();
        consumer();
    }
    
    public static void consumer(){
        System.out.println();
        Consumer consumer = n -> System.out.println("今天消费了"+ n + "元");
        consumer.accept(120);
    }
    
    public static void predicate(){
        List list = Arrays.asList(1, 2, 3, 4, 5);
        Predicate predicate = n -> true;
        System.out.println("输出所有数据:");
        // 传递参数n
        fore(list, predicate);
    }
    
    public static void fore(List list, Predicate predicate) {
        for(Integer n: list) {
            if(predicate.test(n)) {
                System.out.print(n + ", ");
            }
        }
    }
}

// 输出结果
输出所有数据:
1, 2, 3, 4, 5, 
今天消费了120元
Lambda表达式

Lambda表达式:允许把函数作为一个方法的参数,即允许函数作为参数传递到方法中。
语法:(parameters) -> expression 或 (parameters) ->{statements; }。
特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

注意点:

  • Lambda表达式主要用来定义行内执行的方法类型接口。
  • Lambda表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。
  • Lambda表达式中不允许声明一个与局部变量同名的参数或者局部变量。
  • Lambda表达式的局部变量可以不用声明为final,但是不可被后面的代码修改。

变量作用域:lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在lambda 内部修改定义在域外的局部变量,否则会编译错误。
实例:

public class Test02 {

    public static void main(String[] args) {
        test();
    }
    public static void test(){
        // 入参为空
        Ts1 ts1 = () -> System.out.println("无参");
        ts1.t1();

        // 单个参数
        Ts2 ts2 = s -> System.out.println(s);
        ts2.t2("单个参数");

        // 多个参数
        Ts3 ts3 = (s1, s2) -> System.out.println(s1+s2);
        ts3.t3("多个", "参数");
    }

    interface Ts1{
        void t1();
    }

    interface Ts2{
        void t2(String str);
    }

    interface Ts3{
        void t3(String str1, String str2);
    }
}
// 输出结果
无参
单个参数
多个参数
方法引用

方法引用:通过方法的名字来指向一个方法。使用格式为一对冒号 ::。可以使语言的构造更紧凑简洁,减少冗余代码。
常用类型:

  • 对象::实例方法。
  • 类::静态方法。
  • 类::实例方法。

实例:

public class Car {
    // Supplier是jdk1.8的函数式供给型接口
    public static Car create(final Supplier supplier) {
        return supplier.get();
    }
    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
    }
    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }
    public void repair() {
        System.out.println("Repaired " + this.toString());
    }
    public static void main(String[] args) {
        // 构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
        Car car  = Car.create(Car::new);
        Car car1 = Car.create(Car::new);
        Car car2 = Car.create(Car::new);
        Car car3 = new Car();
        List cars = Arrays.asList(car,car1,car2,car3);
        // 静态方法引用:它的语法是Class::static_method,实例如下:
        cars.forEach(Car::collide);
        // 特定类的任意对象的方法引用:它的语法是Class::method实例如下:
        cars.forEach(Car::repair);
        // 特定对象的方法引用:它的语法是instance::method实例如下:
        final Car police = Car.create(Car::new);
        cars.forEach(police::follow);
    }
}
// 输出结果
Collided com.outside.demo.methods.Car@214c265e
Collided com.outside.demo.methods.Car@448139f0
Collided com.outside.demo.methods.Car@7cca494b
Collided com.outside.demo.methods.Car@7ba4f24f
Repaired com.outside.demo.methods.Car@214c265e
Repaired com.outside.demo.methods.Car@448139f0
Repaired com.outside.demo.methods.Car@7cca494b
Repaired com.outside.demo.methods.Car@7ba4f24f
Following the com.outside.demo.methods.Car@214c265e
Following the com.outside.demo.methods.Car@448139f0
Following the com.outside.demo.methods.Car@7cca494b
Following the com.outside.demo.methods.Car@7ba4f24f
接口增强

接口默认方法:接口可以有实现方法,不需要实现类去实现其方法。只需在方法名前面加个default关键字即可实现默认方法。目的是为了解决接口的修改与现有的实现不兼容的问题。
接口静态方法:接口可以声明静态方法,并可提供具体实现。
实例:

public class Test {
    public static void main(String args[]) {
        Te te = new Te();
        te.pr();
    }
}
interface TestInterface {
    default void mr() {
        System.out.println("接口默认方法");
    }
    static void jt() {
        System.out.println("接口静态方法");
    }
}
class Te implements TestInterface {
    public void pr() {
        TestInterface.super.mr();
        TestInterface.jt();
    }
}
// 输出结果
接口默认方法
接口静态方法
Stream API

Stream API:流Stream,以声明的方式处理数据。Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
什么是 Stream?Stream(流)是一个来自数据源的元素队列并支持聚合操作:

  • 元素:是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 :流的来源。可以是集合,数组,I/O channel,产生器generator等。
  • 聚合操作: 类似SQL语句一样的操作,比如filter, map, reduce, find,match, sorted等。

基础特征:

  • Pipelining::中间操作都会返回流对象本身。这样多个操作可以串联成一个管道,如同流式风格(fluent style)。这样做可以对操作进行优化,比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代:以前对集合遍历都是通过Iterator或者For-Each的方式,显式的在集合外部进行迭代,这叫做外部迭代。Stream提供了内部迭代的方式,通过访问者模式(Visitor)实现。

生成流方法:

  • stream() −为集合创建串行流。
  • parallelStream() − 为集合创建并行流。

实例:

public class Test02 {
    public static void main(String args[]) {
        // 计算空字符串
        List strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        long count = strings.stream().filter(string -> string.isEmpty()).count();
        System.out.println("空字符串数量为: " + count);
        count = strings.stream().filter(string -> string.length() == 3).count();
        System.out.println("字符串长度为 3 的数量为: " + count);
        List filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
        System.out.println("筛选后的列表: " + filtered);
        String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
        System.out.println("合并字符串: " + mergedString);
        List numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        List squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
        System.out.println("Squares List: " + squaresList);
        List integers = Arrays.asList(1, 2, 13, 4, 15, 6, 17, 8, 19);
        System.out.println("列表: " + integers);
        IntSummaryStatistics stats = integers.stream().mapToInt((x) -> x).summaryStatistics();
        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());
        System.out.println("随机数2个: ");
        Random random = new Random();
        random.ints().limit(2).sorted().forEach(System.out::println);
        // 并行处理
        count = strings.parallelStream().filter(string -> string.isEmpty()).count();
        System.out.println("空字符串的数量为: " + count);
    }
}
// 输出结果
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数2个: 
-1575488198
107330827
空字符串的数量为: 2
Optional类

Optional类:可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。可以保存类型T的值,或者仅仅保存null。主要解决空指针异常。
类声明:public final class Optional extends Object { }
类方法:

方法说明
static Optional empty()返回空的 Optional 实例
boolean equals(Object obj)判断其他对象是否等于 Optional
Optional filter(Predicate predicate)如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional
Optional flatMap(Function> mapper)如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
T get()如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
int hashCode()返回存在值的哈希码,如果值不存在 返回 0
void ifPresent(Consumer consumer)如果值存在则使用该值调用 consumer , 否则不做任何事情
boolean isPresent()如果值存在则方法会返回true,否则返回 false
Optional map(Function mapper)如果存在该值,提供的映射方法,如果返回非null,返回一个Optional描述结果
static Optional of(T value)返回一个指定非null值的Optional
static Optional ofNullable(T value)如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional
T orElse(T other)如果存在该值,返回值, 否则返回 other
T orElseGet(Supplier other)如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果
T orElseThrow(Supplier exceptionSupplier)如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
String toString()返回一个Optional的非空字符串,用来调试

实例:

public class Test {
    public static void main(String args[]) {
        Test test = new Test();
        Integer value1 = null;
        Integer value2 = new Integer(10);
        // Optional.ofNullable - 允许传递为 null 参数
        Optional a = Optional.ofNullable(value1);
        // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
        Optional b = Optional.of(value2);
        System.out.println(test.sum(a, b));
    }
    public Integer sum(Optional a, Optional b) {
        // Optional.isPresent - 判断值是否存在
        System.out.println("第一个参数值存在: " + a.isPresent());
        System.out.println("第二个参数值存在: " + b.isPresent());
        // Optional.orElse - 如果值存在,返回它,否则返回默认值
        Integer value1 = a.orElse(new Integer(0));
        //Optional.get - 获取值,值需要存在
        Integer value2 = b.get();
        return value1 + value2;
    }
}
// 输出结果
第一个参数值存在: false
第二个参数值存在: true
10
时间日期API

时间日期API:加强对日期与时间的处理。Local(本地) − 简化了日期时间的处理,没有时区的问题。Zoned(时区) − 通过制定的时区处理日期时间。新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
实例:

public class Test {
    public static void main(String args[]) {
        testLocalDateTime();
    }
    public static void testLocalDateTime() {
        // 获取当前的日期时间
        LocalDateTime currentTime = LocalDateTime.now();
        System.out.println("当前时间: " + currentTime);
        LocalDate date = currentTime.toLocalDate();
        LocalDate date1 = LocalDate.now();
        System.out.println("当前日期date: " + date);
        System.out.println("当前日期date1: " + date1);
        int year = currentTime.getYear();
        Month month = currentTime.getMonth();
        int day = currentTime.getDayOfMonth();
        int hour = currentTime.getHour();
        int minute = currentTime.getMinute();
        int seconds = currentTime.getSecond();
        System.out.println("年: " + year +",月: " + month + ", 日: " + day +", 时: " + hour+", 分: " + minute +", 秒: " + seconds);
        // 获取具体某年某月某日日期
        LocalDate date3 = LocalDate.of(2022, Month.JULY, 25);
        System.out.println("date3: " + date3);
        // 获取具体某时某分
        LocalTime date4 = LocalTime.of(6, 0);
        System.out.println("date4: " + date4);
        // 解析字符串
        LocalTime date5 = LocalTime.parse("06:00:00");
        System.out.println("date5: " + date5);
    }
}
// 输出结果
当前时间: 2022-06-24T11:53:27.111
当前日期date: 2022-06-24
当前日期date1: 2022-06-24
年: 2022,月: JUNE, 日: 24, 时: 11, 分: 53, 秒: 27
date3: 2022-07-25
date4: 06:00
date5: 06:00
可重复注解

可重复注解:允许在同一个地方多次使用同一个注解。使用@Repeatable注解定义重复注解。
类型注解:Java 8为@Target元注解新增了两种类型: TYPE_PARAMETER(表示该注解能写在类型参数的声明语句中。 类型参数声明如: ),TYPE_USE(表示注解可以再任何用到类型的地方使用) 。
可重复注解实例:

public class Test {
    // 定义一个重复的注解容器
    @Retention(RetentionPolicy.RUNTIME)
    @interface MYTests{
        MyTest[] value();
    }

    // 定义一个可以重复的注解
    @Retention(RetentionPolicy.RUNTIME)
    @Repeatable(MYTests.class)
    @interface MyTest{
        String value();
    }

    // 配置重复的注解
    @MyTest("test1")
    @MyTest("test2")
    public void test(){

    }

    public static void main(String[] args) {
        // 获取方法上的注解
        try {
            MyTest[] tests = Test.class.getMethod("test").getAnnotationsByType(MyTest.class);
            for (MyTest test : tests) {
                System.out.println("test = " + test);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
// 输出结果
test = @com.outside.demo.repeat.Test$Mytest(value=test1)
test = @com.outside.demo.repeat.Test$Mytest(value=test2)
Nashorn JavaScript引擎

Nashorn:JavaScript引擎。Nashorn取代Rhino(JDK 1.6, JDK1.7)成为Java的嵌入式JavaScript引擎。Nashorn完全支持ECMAScript 5.1规范以及一些扩展。它使用基于JSR292的新语言特性,其中包含在JDK 7中引入的invokedynamic,将JavaScript编译成Java字节码。与先前的Rhino实现相比,带来了2到10倍的性能提升。
jjs:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。
实例:

public class Test {
    public static void main(String args[]){
        ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn");
        String name = "outside";
        Integer result = null;
        try {
            nashorn.eval("print('" + name + "')");
            result = (Integer) nashorn.eval("2");
        }catch(ScriptException e){
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        System.out.println(result);
    }
}
// 输出结果
outside
2
Base64

Base64:Java 8 内置了 Base64 编码的编码器和解码器。
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:

  • 基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
  • URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
  • MIME:输出隐射到MIME友好格式。输出每行不超过76字符,并且使用’r’并跟随’n’作为分割。编码输出最后没有行分割。

内嵌类:

内嵌类说明
static class Base64.Decoder使用 Base64 编码来解码字节数据
static class Base64.Encoder使用 Base64 编码来编码字节数据

方法:

方法说明
static Base64.Decoder getDecoder()解码使用基本型 base64 编码方案
static Base64.Encoder getEncoder()编码使用基本型 base64 编码方案
static Base64.Decoder getMimeDecoder()解码使用 MIME 型 base64 编码方案
static Base64.Encoder getMimeEncoder()编码使用 MIME 型 base64 编码方案
static Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator)编码使用 MIME 型 base64 编码方案,可以通过参数指定每行的长度及行的分隔符
static Base64.Decoder getUrlDecoder()解码使用 URL 和文件名安全型 base64 编码方案
static Base64.Encoder getUrlEncoder()编码使用 URL 和文件名安全型 base64 编码方案

实例:

public class test {
    public static void main(String args[]) {
        try {
            // 使用基本编码
            String base64encodedString = Base64.getEncoder().encodeToString("runoob?java8".getBytes("utf-8"));
            System.out.println("Base64 编码字符串 (基本) :" + base64encodedString);
            // 解码
            byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
            System.out.println("原始字符串: " + new String(base64decodedBytes, "utf-8"));
            base64encodedString = Base64.getUrlEncoder().encodeToString("TutorialsPoint?java8".getBytes("utf-8"));
            System.out.println("Base64 编码字符串 (URL) :" + base64encodedString);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < 10; ++i) {
                stringBuilder.append(UUID.randomUUID().toString());
            }
            byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
            String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
            System.out.println("Base64 编码字符串 (MIME) :" + mimeEncodedString);
        } catch (UnsupportedEncodingException e) {
            System.out.println("Error :" + e.getMessage());
        }
    }
}
// 输出结果
Base64 编码字符串 (基本) :cnVub29iP2phdmE4
原始字符串: runoob?java8
Base64 编码字符串 (URL) :VHV0b3JpYWxzUG9pbnQ_amF2YTg=
Base64 编码字符串 (MIME) :MjQ4NWQ4ZmEtMGM0ZC00MGZhLWFkYWQtM2RlNmUwNTlmNDMwMDdlOGExMGYtOTM1NC00OTk2LTk4
ZjItNzA4MTFkZWRjMjczN2JhOTlmZDQtZmFlMC00ZGMxLTlmMDktNjkyMDJkYmE4YzhiODQzOWM3
M2YtNTBiMi00ZjE3LWE5ZjMtYTY4Y2I5MzgxMDJjOTU2ZjU4NGMtOWY0YS00MGQwLThhZmItYmNj
MmNiZDc0Zjg4NTgyMDM5N2UtNGM4OC00MmQ0LTg5ZDAtNDQ4OGE1YWRiODc1ODMxYzk3M2ItZmZk
OS00OGQzLWI2NmMtNDkyZjc3MzNjZmI0ZjdlMTlkZDItNmYzNi00ZTM1LWI5ZjQtZTM3YzFjYTE4
MDdiMmZkMmUyYTEtODI4MC00MzY2LWEzNDAtZGRkZDdhZmZlNTEzZjNiNmI0YzMtMDg1Yi00Mzg3
LTgyMDAtYWYzNjA0OTM4YTkz
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/993084.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号