java8新特性

1.java8 Lambda表达式

Lambda表达式,也可称为闭包,是推动java8发布的最重要的特性。
Lambda允许函数作为一个方法的参数。
优点:使代码变得更加的简洁紧凑。

1.语法

(parameters)->expression

(parameters)->{statements;}
lambda表达式的重要特性:

  1. 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值
  2. 可选的参数圆括号:一个参数无需定义圆括号,但是多个参数需要定义圆括号
  3. 可选的大括号:如果主题包含了一个语句,就不需要使用大括号
  4. 可选的返回关键字:如果主题只有一个表达式返回值则编译器会自动返回值,大括号需要指定表明表达式返回了一个数值。
public class Java8Tester {
    public static void main(String[] args) {
        Java8Tester tester = new Java8Tester();
        MathOperation addition = (int a, int b) -> a + b;
        MathOperation subtraction = (a, b) -> a - b;
        MathOperation multiplication = (int a, int b) -> {
            return a * b;
        };
        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 * 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        GreetingSerivice greetingSerivice = message ->
                System.out.println("hello " + message);
        GreetingSerivice greetingSerivice2 = message ->
                System.out.println("hello " + message);
        greetingSerivice.sayMessage("Runoob");
        greetingSerivice2.sayMessage("Google");
    }

    interface MathOperation {
        int operation(int a, int b);
    }

    interface GreetingSerivice {
        void sayMessage(String message);
    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }
}

注意两点

  1. Lambda表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。
  2. Lambda表达式免去了使用匿名方法的麻烦,并且给予java简单但是强大的函数化的编程能力。

2.变量作用域

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

public class Java8Tester {
    final static String salutation = "Hello!";
    public static void main(String[] args) {
        GreetingService greetingService = message -> {
            System.out.println(salutation + message);
        };
        greetingService.sayMessage("Runoob");
    }

    interface GreetingService {
        void sayMessage(String message);
    }
}

3.也可以直接在lambda表达式中访问外层的局部变量

public class Java8Tester {
    public static void main(String[] args) {
        final int num = 1;
        Converter<Integer, String> s = (param) ->
                System.out.println(String.valueOf(param + num));
        s.convert(23);
    }

    public interface Converter<T1, T2> {
        void convert(int i);
    }
}

注意:

1.lambda表达式的局部变量可以不用声明为final,但是必须不可被后面的代码修改。(即隐性的具有final的语义)
2.在lambda表达式中不允许声明一个与局部变量同名的参数或者局部变量。

public class Java8Tester {
    public static void main(String[] args) {
        int num = 1;
        Converter<Integer, String> s = (param) ->
                System.out.println(String.valueOf(param + num)); // 这里的param不能改为num,如果与局部变量的名同样,会报错。
        s.convert(23);
        num = 5; // 将这行注释掉,不然会报错
    }

    public interface Converter<T1, T2> {
        void convert(int i);
    }
}

2.java8 方法引用

方法引用通过方法的名字来指向一个方法。
方法引用使用一对冒号::

1.方法应用

import java.util.Arrays;
import java.util.List;

public class Car {
    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }

    public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
    }

    public static void collide(final Car car) {
        System.out.println("Collied " + 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) {
        Car car = Car.create(Car::new);
        Car car1 = Car.create(Car::new);
        Car car2 = Car.create(Car::new);
        Car car3 = new Car();

        List<Car> cars = Arrays.asList(car, car1, car2, car3);
        System.out.println("==================构造器引用=================");
        cars.forEach(Car::collide);
        System.out.println("==================静态方法引用==================");
        cars.forEach(Car::repair);
        System.out.println("==================特定类的任意对象的方法引用==================");
        final Car police = Car.create(Car::new);
        cars.forEach(police::follow);
        System.out.println("==================特定对象的方法引用==================");
    }
}

运行结果:
==================构造器引用=================
Collied Car@214c265e
Collied Car@448139f0
Collied Car@7cca494b
Collied Car@7ba4f24f
==================静态方法引用==================
Repaired Car@214c265e
Repaired Car@448139f0
Repaired Car@7cca494b
Repaired Car@7ba4f24f
==================特定类的任意对象的方法引用==================
following the Car@214c265e
following the Car@448139f0
following the Car@7cca494b
following the Car@7ba4f24f
==================特定对象的方法引用==================

2.方法引用

实际上我们将System.out::println方法作为静态方法来引用。

import java.util.ArrayList;
import java.util.List;

public class Car {
    public static void main(String[] args) {
        List names = new ArrayList();
        names.add("Google");
        names.add("Runoob");
        names.add("Taobao");
        names.add("Baidu");
        names.add("sina");
        names.forEach(System.out::println);

    }
}

3.java8 函数式接口

函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为lambda表达式。
函数式接口可以现有的函数友好地支持lambda.
jdk1.8之前已有的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
JDK 1.8新增加的函数接口
java.util.function
它包含很多类,用来支持java的函数式编程,该包中的函数式接口有:
Predicate:该接口是一个函数式接口,他接受一个输入参数T,返回一个布尔值结果。
该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)
该接口用于测试对象是true或false

public class Car {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Predicate<Integer> predicate = n -> true;
        eval(list, predicate);  // 结果为1 2 3 4 5 6 7 8 9
        System.out.println("\n---------------");
        Predicate<Integer> p2 = n -> n % 2 == 0;
        eval(list, p2); // 结果为2 4 6 8
        System.out.println("\n---------------");
        Predicate<Integer> p3 = n -> n > 3;
        eval(list, p3); // 结果为4 5 6 7 8 9 
    }

    public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for (Integer n : list) {
            if (predicate.test(n)) {
                System.out.print(n + " ");
            }
        }
    }
}

4. java8 默认方法

默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个default关键字即可实现默认方法。
为什么要有这个特性?
优点:面向抽象而不是面向具体编程,
缺点:当需要修改接口时候,需要修改全部实现该接口的类,目前的java8之前的集合框架foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。
然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。目的是为了解决接口的修改与现有的实现不兼容的问题。

1.语法

public interface vehicle {
    default void print() {
        System.out.println("我是一辆车!!");
    }
}

2.多个默认方法

一个接口有默认方法,考虑这样的情况,一个类实现了多个接口,且这些接口有相同的默认的方法,实例如下:

接口vehicle:
public interface vehicle {
    default void print() {
        System.out.println("我是一辆普通车!!");
    }
}

接口fourWheeler:
public interface fourWheeler {
    default void print() {
        System.out.println("我是一辆四轮车!!!");
    }
}

类Car:
public class Car implements vehicle, fourWheeler {
    /*@Override
    public void print() {
        System.out.println("我是一辆劳斯莱斯!!!"); // 输出“我是一辆劳斯莱斯!!!”
    }*/

    @Override
    public void print() {
        fourWheeler.super.print(); // 输出“我是一辆四轮车!!!”
    }
}

类test:
public class test {
    public static void main(String[] args) {
        Car car = new Car();
        car.print();
    }
}

3.静态默认方法

java8 的另一个特性是接口可以声明(并且可以提供实现)静态方法。例如:

public interface vehicle {
    // 静态方法
    static void blowHorn() {
        System.out.println("按喇叭!!!");
    }
}

4.默认方法实例

public class Java8Tester {
    public static void main(String[] args) {
        Vehicle vehicle = new Car();
        vehicle.print();
    }
}

interface Vehicle {
    default void print() {
        System.out.println("我是一辆车!!!");
    }

    static void blowHorn() {
        System.out.println("按喇叭!!!");
    }
}

interface FourWheeler {
    default void print() {
        System.out.println("我是一辆四轮车!!!");
    }
}

class Car implements Vehicle, FourWheeler {
    @Override
    public void print() {
        Vehicle.super.print(); // 我是一辆车!!!
        FourWheeler.super.print(); // 我是一辆四轮车!!!
        Vehicle.blowHorn(); // 按喇叭!!!
        System.out.println("我是一辆小汽车!!!"); // 我是一辆小汽车!!!
    }
}

5. Java8 Stream

Java8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的结点上进行处理,比如:筛选,排序,聚合等。
元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
什么是Stream?

  1. Stream是一个来自数据源的元素队列并支持聚合操作。
    元素:是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
    数据源:流的来源。可以是集合,数组,I/O channel,产生器generator等。
    聚合操作:类似SQL语句一样的操作,比如filter,map,reduce,find,match,sorted等。
  2. 和以前的Collection操作不同,Stream操作还有两个基础的特征:
    Pipelining:  中间操作都会返回流对象本身.这样多个操作可以串联成一个管道,如同流式风格.这样做可以对操作进行优化.比如延迟执行和短路(short-circuiting)
    内部迭代:  以前对集合遍历都是通过Iterator或者For-Each的方式,显式的在集合外部进行迭代,这叫做外部迭代.Stream提供了内部迭代的方式,通过访问者模式实现.

生成流
在Java8中,集合接口有两个方法来生成流:
stream()--为集合创建串行流.
parallelStream()--为集合创建并行流.
filter

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Java8Tester {
    public static void main(String[] args) {
        List<String> strings = 
            Arrays
                .asList("abc", "",
                        "bc", "efg",
                        "abcd", "", "jkl");
        List<String> filtered =
            strings
                .stream()
                .filter(string ->
                        !string.isEmpty())
                // 过滤空字符串
                .collect(Collectors.toList());
        for (String s : filtered) {
            System.out.println(s);
        }
    }
}

forEach,limit

import java.util.Random;

public class Java8Tester {
    public static void main(String[] args) {
        Random random = new Random();
        random.ints().limit(5).forEach(System.out::println);
        // forEach用来遍历,limit用来限制输出5条数据    
    }
}

map
map方法用于映射每个元素到对应的结果

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

public class Java8Tester {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        List<Integer> collect =
                numbers
                        .stream()
                        .map(i -> i * i)
                        // 使用map输出了元素对应的平方数
                        .distinct()
                        .collect(Collectors.toList());
        for (Integer i : collect) {
            System.out.println(i);
        }
    }
}

sorted
用于对流进行排序

import java.util.Random;

public class Java8Tester {
    public static void main(String[] args) {
        Random random = new Random();
        random.ints().limit(10).sorted().forEach(System.out::println);
    }
}

并行(parallel)程序
parallelStream是流并行处理程序的代替方法.

import java.util.Arrays;
import java.util.List;

public class Java8Tester {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        int count = (int) strings.parallelStream().filter(string -> !string.isEmpty()).count();
        System.out.println(count); // 5
    }
}

Collectors
Collectors类实现了很多归约操作,例如将流转换成集合和聚合元素.Collectors可用于返回列表或字符串:

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List; 

public class Java8Tester {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        IntSummaryStatistics stats = numbers.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());
    }
}

6. Java8 Optional类

Optional类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象.
Optional是个容器:它可以保存类型T的值,或者仅仅保存null.
Optional提供很多有用的方法,这样我们就不用显示进行空值检测.
Optional类的引入很好的解决空指针异常.
1. 类声明
public final class Optional<T> extends Object
2. 类方法
这些方法都是从java.lang.Object类继承来的
3. Optional实例

import java.util.Optional;

public class Java8Tester {
    public static void main(String[] args) {
        Java8Tester java8Tester = new Java8Tester();
        Integer value1 = null;
        Integer value2 = new Integer(10);
        // Optional.ofNullable -- 允许传递为null参数
        Optional<Integer> a = Optional.ofNullable(value1);
        // Optional.of -- 如果传递的参数是null, 抛出异常NullPointerException
        Optional<Integer> b = Optional.of(value2);
        System.out.println(java8Tester.sum(a, b));
    }

    public Integer sum(Optional<Integer> a, Optional<Integer> 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;
    }
}

7. Java8 Nashorn JavaScript

Nashorn 一个javascript引擎.
从JDK1.8开始,Nashorn取代Rhino(JDK1.6, JDK1.7)成为Java的嵌入式JavaScript引擎.
Nashorn完全支持ECMAScript5.1规范以及一些扩展.它使用基于JSR292的新语言特性,其中包含在JDK7中引入的invokedynamic,将JavaScript编译成Java字节码.
与先前的Rhino实现相比,这带来了2到10倍的提升.
1. jjs
jjs是个基于Nashorn引擎的命令工具.他接受一些JavaScript源代码为参数,并且执行这些源代码.
例如,创建一个具有如下内容的sample.js文件:
print('Hello World!')
打开控制台,输入该命令 $jjs sample.js
输出结果为:Hello World!
2. jjs交互式编程
打开控制台,输入以下命令

$ jjs
jjs> print("Hello World!")
Hello World!
jjs> quit()
>>

3. 传递参数
打开控制台,输入以下命令

$ jjs -- a b c
jjs> print('字母:' + arguments.join(", "))
字母: a, b, c
jjs>

4. java中调用JavaScript
使用ScriptEngineManager, JavaScript代码可以在Java中执行,实例如下:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Java8Tester {
    public static void main(String[] args) {
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");

        String name = "Runoob";
        Integer result = null;

        try {
            nashorn.eval("print('" + name + "')");
            result = (Integer) nashorn.eval("10 + 2");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
        System.out.println(result.toString());
    }
}

// 结果为 Runoob 12

5. JavaScript中调用Java

varBigDecimal = Java.type('java.math.BigDecimal');
function calculate(amount, percentage) {
    var result = newBigDecimal(amount).multiply(
    newBigDecimal(percentage)).divide(newBigDecimal("100"), 2, BigDecimal.ROUND_HALF_EVEN);
    return result.toPlainString();
}

var result = calculate(568);
print(result);

8. Java8 日期时间API

Java8 通过发布新的Date-Time API(JSR 310)来进一步加强对日期与时间的处理.

在旧版的Java中,日期API存在诸多问题,其中有:

  1. 非线程安全---java.util.Date是非线程安全的,所有日期类都是可变的,这是Java日期类最大的问题之一.
  2. 设计很差---Java的日期/时间类的定义不一致,在Java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义.
    java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理.另外这两个类都用相同的设计,本身就是个非常糟糕的设计.
  3. 时区处理麻烦---日期类并不提供国际化,没有时区支持,因此java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有问题.
    Java8在Java.time包下提供了很多新的API.
    1.Local(本地)---简化了日期时间的处理,没有时区的问题.
    2.Zoned(时区)---通过制定的时区处理日期时间.
    新的java.tima包,涵盖了所有处理日期,时间,日期/时间,时区,时刻,过程与时钟的操作.
    1. 本地化日期时间API
    LocalDate/LocalTime和LocalDateTime类可以在处理时区不是必须的情况.
import java.time.*;

public class Java8Tester {
    public static void main(String[] args) {
        Java8Tester java8Tester = new Java8Tester();
        java8Tester.testZonedDateTime();
    }

    public void testZonedDateTime() {
        // 获取当前时间日期
        LocalDateTime currentTime = LocalDateTime.now();
        System.out.println("当前时间:" + currentTime); // 当前时间:2022-02-24T11:23:08.297
        LocalDate date1 = currentTime.toLocalDate();
        System.out.println("date1: " + date1); // date1: 2022-02-24
        Month month = currentTime.getMonth();
        int day = currentTime.getDayOfMonth();
        int seconds = currentTime.getSecond();
        // 月:FEBRUARY,日:24:秒:8
        System.out.println("月:" + month + ",日:" + day + ":秒:" + seconds);
        LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
        System.out.println("date2: " + date2); // date2: 2012-02-10T11:23:08.297
        LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
        System.out.println("date3: " + date3); // date3: 2014-12-12
        LocalTime date4 = LocalTime.of(22, 15);
        System.out.println("date4: " + date4); // date4: 22:15
        // 解析字符串
        LocalTime date5 = LocalTime.parse("20:15:30");
        System.out.println("date5: " + date5); // date5: 20:15:30
    }
}

2. 使用时区的日期时间API
如果我们需要考虑到时区,就可以使用时区的日期时间API:
Java8Tester.java文件

import java.time.*;

public class Java8Tester {
    public static void main(String[] args) {
        Java8Tester java8Tester = new Java8Tester();
        java8Tester.testZonedDateTime();
    }

    public void testZonedDateTime() {
        // 获取当前时间日期
        ZonedDateTime date1 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
        System.out.println("date1: " + date1); // date1: 2015-12-03T10:15:30+08:00[Asia/Shanghai]
        ZoneId id = ZoneId.of("Europe/Paris");
        System.out.println("ZoneId: " + id); // ZoneId: Europe/Paris
        ZoneId currentZone = ZoneId.systemDefault();
        System.out.println("当期时区: " + currentZone); // 当期时区:  Asia/Shanghai
    }
}

9. Java8 Base64

在java8中,Base64编码已经成为Java类库的标准。
Java8内置了Base64编码器和解码器。
Base64工具类提供了一套静态方法获取下面三种BASE64编解码:

  • 基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
  • URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
  • MIME:输出映射到到MIME友好格式。输出每行不超过76个字符,并且使用'\r'并跟随'\n'做分割。编码输出最后没有行分割。
    1. 内嵌类
1.static class Base64.Decoder
该类实现一个解码器用于,使用Base64编码来解码字节数据
2.static class Base64.Encoder
该类实现一个编码器,使用Base64编码来编码字节数据

2. 方法

1. static Base64.Decoder.getDecoder()
返回一个Base64.Decoder,解码使用基本类型base64编码方案
2. static Base64.Encoder.getEncoder()
返回一个Base64.Enocder,编码使用基本型base64编码方案
3. static.Base64.Decoder getMimeDecoder()
返回一个Base64.Decoder,解码使用MIME型base64编码方案
4. static Base64.Encoder getMimeEncoder()
返回一个Base64.Encoder,编码使用MIME型base64编码方案
5. static Base64.Encoder getMimeEnoder(int lineLength, byte[] lineSeparator)
返回一个Base64.Encoder,编码使用MIME型base64编码方案,可以通过参数指定每行的长度及行的分隔符
6. static Base64.Decoder getUrlDecder()
返回一个Base64.Decoder,解码使用URL和文件名安全型base64编码方案
7. static Base64.Encoder getUrlEncoder()
返回一个Base64.Encoder,解码使用URL和文件名安全型base64编码方案

3.Base64实例

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.UUID;

public class Java8Tester {
    public static void main(String[] args) {
        try {
            // 使用基本编码
            String base64encodedString = Base64.getEncoder().encodeToString("runoob?java8".getBytes("utf-8"));
            System.out.println("Base64编码字符串(基本):" + base64encodedString); // Base64编码字符串(基本):cnVub29iP2phdmE4

            // 解码
            byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
            System.out.println("原始字符串:" + new String(base64decodedBytes, "utf-8")); // 原始字符串:runoob?java8

            base64encodedString = Base64.getUrlEncoder().encodeToString("TutorialsPoint?java8".getBytes("utf-8"));
            System.out.println("Base64 编码字符串(URL):" + base64encodedString); // Base64 编码字符串(URL):VHV0b3JpYWxzUG9pbnQ_amF2YTg=

            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);
            /*
            Base64编码字符串(MIME):
            OTM2NGIxNGEtYWViNS00OGFmLWE5ODMtZjAzNjA2NzM5OTIzZGI2NGI3NWUtOWMzNC00NzAxLTk5
            NGEtMDFjM2JjZWFjZGNlMmIwYTIyYzgtNGRlOS00OGNjLWJmMjMtZDc0NDIxNTA1OTlkOTVjNzUw
            NTMtNjNkNi00NTI4LWEzY2EtOTlhYzAyYmNhOTU4OTg1YjM2NTAtMzRlMC00Njc0LTg2MWYtMjdm
            Nzg2ZjFiNzQwYjJlY2FhYmUtYmM4My00NmNlLTgwYmEtOTYwMjU1OWY2NDYwMjYxN2QwNmEtNDRi
            NC00MmZjLWJlMTQtOWFjZjI3ODE4ZWRhNTFlMGQ3YTItYTQyMC00MWYyLTk4NWQtNTczNTFmYjgy
            OTM5YjdmM2RlMDEtZjMwOS00MThhLTk4NDQtZThiYTM2YmQ3NTFmMzYwZTFiMzgtZDM5MS00ZDM2
            LTliYmItZTYxZTc2MDMzZDZl
             */
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
posted @ 2022-02-24 14:45  jsqup  阅读(32)  评论(0编辑  收藏  举报