程序员

优雅编程 - 语法糖

2019-12-19  本文已影响0人  林昀熙

本篇采用示例的形式展示Java8的常见特性应用.

线程写法

Java8之前

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("自定义线程");
    }
}).start();

Java8写法

new Thread(()-> {
    System.out.println("自定义线程");
}).start();

比较器写法

Java8之前

List<String> list = Arrays.asList("bb", "a", "ccc");
Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.length() - o2.length();
    }
});
// [a, bb, ccc]
System.out.println(list);

Java8写法

Collections.sort(list, (o1, o2) -> o1.length() - o2.length());
// [a, bb, ccc]
System.out.println(list);

遍历写法

Java8之前

List<String> list = Arrays.asList("bb", "a", "ccc");
for (String li : list) {
    System.out.println(li);
}

Java8写法

List<String> list = Arrays.asList("bb", "a", "ccc");
list.forEach(li -> System.out.println(li));
list.forEach(System.out::println);

计算过滤

List<Integer> numbers = Arrays.asList(20,22,1,2,1,3,3,2,4,8,16);
// 过滤集合中的偶数,去重、排序
List<Integer> filters = numbers.stream().filter(i -> i % 2 == 0).distinct().sorted().collect(Collectors.toList());
// 248162022
filters.forEach(System.out::print);

对列表每个元素应用函数

List<String> list = Arrays.asList("USA", "Japan", "France", "Germany", "Italy","Canada");
// 将字符串换成大写并用点号链接起来
String str = list.stream().map(x -> x.toUpperCase()).collect(Collectors.joining("、"));
// USA、JAPAN、FRANCE、GERMANY、ITALY、CANADA
System.out.println(str);

lambda表达式中的Map Reduce

List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400);
double bill = costBeforeTax.stream().map((cost) -> cost + .10*cost).reduce((sum, cost) -> sum + cost).get();
// 1100.0
System.out.println("集合中的元素每个增大10%后的结果总和: " + bill);

集合元素计算

List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.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());

集合元素分组

public static void main(String[] args) {
   List<Person> list = Arrays.asList(new Person(10, "Elon"), new Person(12, "Dennisit"), new Person(10, "Alone"));
   // [{"age":10,"name":"Elon"}, {"age":12,"name":"Dennisit"}, {"age":10,"name":"Alone"}]
   System.out.println(list);
   Map<Integer, List<Person>> groupByAge = list.stream().collect(Collectors.groupingBy(Person::getAge, Collectors.toList()));
   // {10=[{"age":10,"name":"Elon"}, {"age":10,"name":"Alone"}], 12=[{"age":12,"name":"Dennisit"}]}
   System.out.println(groupByAge);
   List<String> names = list.stream().map(e->e.getName()).collect(Collectors.toList());
   // [Elon, Dennisit, Alone]
   System.out.println(names);
   List<Integer> ages = list.stream().map(e->e.getAge()).distinct().collect(Collectors.toList());
   // [10, 12]
   System.out.println(ages);
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class Person{
   private int age;
   private String name;

   public String toString(){
       return JSON.toJSONString(this);
   }
}

集合对象排序

public static void main(String[] args) {
    List<Person> list = Arrays.asList(new Person(10, "Elon"), new Person(12, "Dennisit"), new Person(10, "Alone"));
    // 按照年龄降序
    List<Person> sort = list.stream()
            .sorted(Comparator.comparing(Person::getAge).reversed())
            .collect(Collectors.toList());
    // [{"age":12,"name":"Dennisit"}, {"age":10,"name":"Elon"}, {"age":10,"name":"Alone"}]
    System.out.println(sort);
}

函数式接口

// 函数接口定义
Predicate<String> startWithJ = (n) -> n.startsWith("J");
Predicate<String> containedA = (n) -> n.contains("a");

List<String> languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
// 使用逻辑函数合并Predicate 执行结果: Java,Scala,Haskell,
languages.stream().filter(startWithJ.or(containedA)).forEach(li -> System.out.print(li + ","));

函数接口应用

我们在用全文索引的时候需要将数据先存储到索引然后进行搜索,索引数据一般操作有全量索引、增量索引、实施索引, 索引创建方式可能有databus、基于消息机制、或者基于定时任务等等.

通常我们把DB数据转换为搜索引擎的索引的时候,分两步:

针对这个行为我们来定义行为规约, 函数接口定义时使用@FunctionalInterface

筛选数据行为
/**
 * 筛选数据行为规约
 */
@FunctionalInterface
public interface DataCriteria<T> {

    /**
     * 分页加载数据
     * @param page 页码
     * @param size 页量
     * @return 加载的数据集合
     */
    public List<T> loader(int page, int size);

}
索引数据行为规约
/**
 * 索引数据行为规约
 */
@FunctionalInterface
public interface IndexCriteria {

    /**
     * 数据索引行为
     * @param list 待索引的数据
     * @return
     */
    public void index(List<?> list);

}

全量索引行为抽象


/**
 * 每次批量处理的数据一次最大500个
 */
public static final Integer DEFAULT_BATCH_SIZE = 500;

/**
 * 私有化构造
 */
private IndexAction(){

}


/**
 * 执行全量索引
 * @param dataCriteria 数据加载行为
 * @param indexCriteria 索引数据行为
 */
public static void fullyIndex(DataCriteria dataCriteria, IndexCriteria indexCriteria) {
    fullyIndex(DEFAULT_BATCH_SIZE, dataCriteria, indexCriteria);
}


/**
 * 执行全量索引
 * @param size 每个批次索引的数据大小
 * @param dataCriteria 数据加载行为
 * @param indexCriteria 索引数据行为
 */
public static void fullyIndex(int size, DataCriteria dataCriteria, IndexCriteria indexCriteria) {
    // 游标页从第一页开始
    int current = 1;
    // 约束批量处理的大小
    size = NumberUtils.restrainNum(size, 0, DEFAULT_BATCH_SIZE);
    while(true){
        int cursor = cursor(current, size, dataCriteria, indexCriteria);
        if (cursor == current) {
            LOG.info("[创建索引] 创建完成, {}*{}数据", size, cursor);
            break;
        }
        current = cursor;
    }
}

/**
 * 游标扫描处理
 * @param page 游标页
 * @param size 每个批次索引的数据大小
 * @param dataCriteria 数据加载行为
 * @param indexCriteria 索引数据行为
 * @return
 */
private static int cursor(int page, int size, DataCriteria dataCriteria, IndexCriteria indexCriteria){
    Assert.notNull(dataCriteria, "数据操作不能为空");
    Assert.notNull(indexCriteria, "操作操作不能为空");
    List list = dataCriteria.loader(page, size);
    if(CollectionUtils.isNotEmpty(list)){
        indexCriteria.index(list);
        ++ page;
    }
    return page;
}

上面我们做了简单的全量索引行为抽象, 从第一页开始分页加载数据进行索引,直到我们加载到的数据为空,本次索引行为结束

特定索引行为抽象

/**
 * 指定数据索引
 * @param list 待索引数据
 * @param indexCriteria 索引行为
 */
public static void pointIndex(List<?> list, IndexCriteria indexCriteria){
    if(CollectionUtils.isEmpty(list)){
        return;
    }
    Assert.notNull(indexCriteria, "操作操作不能为空");
    indexCriteria.index(list);
}

该抽象比较简单,直接进行指定的数据索引即可.

规约使用

上面我们定义了规约, 接下来直接展示如何优雅的基于规约装载数据

/**
 * 全量索引
 */
@Override
public void fullyIndex() {
    IndexAction.fullyIndex(
            // 分页加载数据
            (p, s) -> {
                return merchantService.selectList(p, s);
            },
            // 数据进行索引
            (x)-> merchantEsRepository.indexList((List<MerchantIndex>)x)
    );
}

/**
 * 特定索引
 * @param ids 主键编号集合
 * @throws Exception
 */
@Override
public void pointIndex(List<Integer> ids) throws Exception{
    List<MerchantIndex> list = merchantService.selectList(ids);
    IndexAction.pointIndex(list, (x) -> merchantEsRepository.indexList((List<MerchantIndex>) x));
}

示例中分别展示了全量索引和特定数据索引的规约应用,通过函数接口功能打包.我们把全量和增量的行为就隐藏在了规约行为中,使业务代码更简洁优雅.

接口方法

public static void main(String[] args) {
    MathOperation addition = (int a, int b) -> a + b;
    // 默认方法
    addition.print();
    // 9
    System.out.println(addition.operation(5, 4));
}

interface MathOperation {

    // 接口方法
    int operation(int a, int b);

    default void print(){
        System.out.println("默认方法");
    }
}

Java8日期操作

/创建日期
LocalDate date = LocalDate.of(2017,1,21); //2017-01-21
int year = date.getYear() //2017
Month month = date.getMonth(); //JANUARY
int day = date.getDayOfMonth(); //21
DayOfWeek dow = date.getDayOfWeek(); //SATURDAY
int len = date.lengthOfMonth(); //31(days in January)
boolean leap = date.isLeapYear(); //false(not a leap year)

//时间的解析和格式化
LocalDate date = LocalDate.parse("2017-01-21");
LocalTime time = LocalTime.parse("13:45:20");

LocalDateTime now = LocalDateTime.now();
now.format(DateTimeFormatter.BASIC_ISO_DATE);

//合并日期和时间
LocalDateTime dt1 = LocalDateTime.of(2017, Month.JANUARY, 21, 18, 7);
LocalDateTime dt2 = LocalDateTime.of(localDate, time);
LocalDateTime dt3 = localDate.atTime(13,45,20);
LocalDateTime dt4 = localDate.atTime(time);
LocalDateTime dt5 = time.atDate(localDate);

//操作日期
LocalDate date1 = LocalDate.of(2014,3,18); //2014-3-18
LocalDate date2 = date1.plusWeeks(1); //2014-3-25
LocalDate date3 = date2.minusYears(3); //2011-3-25
LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS); //2011-09-25

日期格式化

java.util.date和java.time.LocalDateTime格式化

应用示例
/**
* 格式化日期
* @param date 待格式化的日期
* @param pattern 格式化正则
* @return 格式化结果串
*/
public static String format(Date date, String pattern){
   return new SimpleDateFormat(pattern).format(date);
}

/**
* 格式化日期
* @param localDateTime 待格式化的日期
* @param pattern 格式化正式
* @return 格式化结果串
*/
public static String format(LocalDateTime localDateTime, String pattern){
   return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
}

/**
* 格式化日期
* @param localDate 待格式化的日期
* @param pattern 格式化正则, 这里使用的类型 {@link LocalDate}, 所以正则只能设定到天
* @return 格式化结果串
*/
public static String format(LocalDate localDate, String pattern){
   return localDate.format(DateTimeFormatter.ofPattern(pattern));
}
示例测试
// 2017-08-28 15:45:02
System.out.println(format(new Date(), "yyyy-MM-dd HH:mm:ss"));
// 2017-08-28 15:45:02
System.out.println(format((LocalDateTime.now()), "yyyy-MM-dd HH:mm:ss"));
// 2017-08-28
System.out.println(format((LocalDateTime.now().toLocalDate()), "yyyy-MM-dd"));

日期转换

java.util.date和java.time.LocalDateTime互相转换

应用示例
/**
* 将 {@link LocalDateTime} 转换成 {@link Date}
* @param localDateTime {@link LocalDateTime} 待转换的日期
* @return 转换成Date结果
*/
public static Date from(LocalDateTime localDateTime){
   Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
   return Date.from(instant);
}

/**
* 将 {@link Date} 转换成 {@link LocalDateTime}
* @param date {@link Date} 待转换的日期
* @return 转换成 {@link LocalDateTime} 结果
*/
public static LocalDateTime from(Date date){
   return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
示例测试
String patternTime = "yyyy-MM-dd HH:mm:ss";
Date now = new Date();
// 2017-08-28 14:47:10
System.out.println(format(from(now), patternTime));
// 2017-08-28 14:47:10
System.out.println(format(from(LocalDateTime.now()), patternTime));

日期区间集合

计算两端日期之间内的日期天数集合

示例代码
/**
* 获取{@link Date}在开始时间和结束时间内的日期时间段{@link Date}集合
* @param start 开始时间
* @param end 结束时间
* @return 时间天数集合
*/
public static List<Date> dateZones(Date start, Date end){
   return dateZones(from(start), from(end));
}


/**
* 获取 {@link LocalDate} 在开始时间和结束时间内的日期时间段 {@link LocalDate} 集合
* @param start 开始时间
* @param end 结束时间
* @return 时间集合
*/
public static List<Date> dateZones(LocalDate start, LocalDate end){
   return Stream.iterate(start, x -> x.plusDays(1))
           .limit(ChronoUnit.DAYS.between(start, end) + 1)
           .map(e -> Date.from(e.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()))
           .collect(Collectors.toList());
}

    
/**
* 获取{@link LocalDateTime} 在开始时间和结束时间内的日期时间段{@link Date}集合
* @param start 开始时间
* @param end 结束时间
* @return 时间天数集合
*/
public static List<Date> dateZones(LocalDateTime start, LocalDateTime end){
   // 用起始时间作为流的源头,按照每次加一天的方式创建一个无限流
   return Stream.iterate(start.toLocalDate(), x -> x.plusDays(1))
           // 截断无限流,长度为起始时间和结束时间的差+1个
           .limit(ChronoUnit.DAYS.between(start, end) + 1)
           // 由于最后要的是字符串,所以map转换一下
           .map(e -> Date.from(e.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()))
           // 把流收集为List
           .collect(Collectors.toList());
}


/**
* 获取{@link Date}在开始时间和结束时间内的日期时间段{@link LocalDate}集合
* @param start 开始时间
* @param end 结束时间
* @return 时间集合
*/
public static List<LocalDate> localDateZones(Date start, Date end){
   return localDateZones(from(start), from(end));
}


/**
* 获取 {@link LocalDate} 在开始时间和结束时间内的日期时间段 {@link LocalDate} 集合
* @param start 开始时间
* @param end 结束时间
* @return 时间集合
*/
public static List<LocalDate> localDateZones(LocalDate start, LocalDate end){
   return Stream.iterate(start, x -> x.plusDays(1))
           .limit(ChronoUnit.DAYS.between(start, end) + 1)
           .collect(Collectors.toList());
}

/**
* 获取 {@link LocalDateTime} 在开始时间和结束时间内的日期时间段 {@link LocalDate} 集合
* @param start 开始时间
* @param end 结束时间
* @return 时间集合
*/
public static List<LocalDate> localDateZones(LocalDateTime start, LocalDateTime end){
   // 用起始时间作为流的源头,按照每次加一天的方式创建一个无限流
   return Stream.iterate(start.toLocalDate(), x -> x.plusDays(1))
           // 截断无限流,长度为起始时间和结束时间的差+1个
           .limit(ChronoUnit.DAYS.between(start, end) + 1)
           .map(e -> e.atStartOfDay().toLocalDate())
           // 把流收集为List
           .collect(Collectors.toList());
}
示例测试
String patternDate = "yyyy-MM-dd";
List<Date> dateList = Arrays.asList(new Date(2017-1900, 11, 30), new Date(2018-1900, 0, 3));

// 2017-12-30
System.out.println("开始时间:"  + format(dateList.get(0), patternDate) + ", 结束时间:" + format(dateList.get(1), patternDate));

// [2017-12-30, 2017-12-31, 2018-01-01, 2018-01-02, 2018-01-03]
System.out.println(dateZones(dateList.get(0), dateList.get(1)).stream().map(x -> format(x, patternDate)).collect(Collectors.toList()));
// [2017-12-30, 2017-12-31, 2018-01-01, 2018-01-02, 2018-01-03]
System.out.println(localDateZones(dateList.get(0), dateList.get(1)).stream().map(x -> format(x, patternDate)).collect(Collectors.toList()));


LocalDateTime now = LocalDateTime.of(2017, Month.DECEMBER, 30, 0, 0, 0);

// 2017-12-30
System.out.println(format(now, patternDate));

// [2017-12-30, 2017-12-31, 2018-01-01, 2018-01-02, 2018-01-03]
System.out.println(dateZones(now, now.plus(4, ChronoUnit.DAYS))
      .stream().map(x -> format(x, patternDate)).collect(Collectors.toList()));

// [2017-12-30, 2017-12-31, 2018-01-01, 2018-01-02, 2018-01-03]
System.out.println(localDateZones(now, now.plus(4, ChronoUnit.DAYS))
      .stream().map(x -> format(x, patternDate)).collect(Collectors.toList()));

// [2017-12-30, 2017-12-31, 2018-01-01, 2018-01-02, 2018-01-03]
System.out.println(localDateZones(now.toLocalDate(), now.toLocalDate().plus(4, ChronoUnit.DAYS))
      .stream().map(x -> format(x, patternDate)).collect(Collectors.toList()));

日期加减

示例代码
String patternDate = "yyyy-MM-dd HH:mm:ss";

LocalDateTime now = LocalDateTime.of(2017, Month.DECEMBER, 30, 0, 0, 0);

// 当前时间: 2017-12-30 00:00:00
System.out.println("当前时间: " + format(now, patternDate));

// 30秒前: 2017-12-29 23:59:30
System.out.println("30秒前: " + format(now.plus(-30, ChronoUnit.SECONDS), patternDate));

// 5分钟后: 2017-12-30 00:05:00
System.out.println("5分钟后: " + format(now.plus(5, ChronoUnit.MINUTES), patternDate));

// 2天前: 2017-12-28 00:00:00
System.out.println("2天前: " + format(now.plus(-2, ChronoUnit.DAYS), patternDate));

// 2天后: 2018-01-01 00:00:00
System.out.println("2天后: " + format(now.plus(2, ChronoUnit.DAYS), patternDate));

// 1周后: 2018-01-06 00:00:00
System.out.println("1周后: " + format(now.plusWeeks(1), patternDate));
        
// 1月前: 2017-11-30 00:00:00
System.out.println("1月前: " + format(now.plus(-1, ChronoUnit.MONTHS), patternDate));

// 1月后: 2018-01-30 00:00:00
System.out.println("1月后: " + format(now.plus(1, ChronoUnit.MONTHS), patternDate));

// 1年后: 2018-12-30 00:00:00
System.out.println("1年后: " + format(now.plus(1, ChronoUnit.YEARS), patternDate));

日期推算

示例代码
String patternDate = "yyyy-MM-dd";

LocalDateTime now = LocalDateTime.of(2017, Month.DECEMBER, 30, 0, 0, 0);

// 当前时间: 2017-12-30
System.out.println("当前时间: " + format(now, patternDate) + " ,是否闰年: " + now.toLocalDate().isLeapYear());

// 当前月份: 十二月
System.out.println("当前月份: " + Month.from(now).getDisplayName(TextStyle.FULL, Locale.CHINA));

// 当前星期: 星期六
System.out.println("当前星期: " + DayOfWeek.from(now).getDisplayName(TextStyle.FULL, Locale.CHINA));

// 需要注意:java8提供的获取的本周第一天和本周最后一天是西方的界定方式, 第一天是周末, 最后一天是周六, 和中国的不太一样
// 本周初第一天:2017-12-24
System.out.println("本周初第一天: " + format(now.with(WeekFields.of(Locale.CHINA).dayOfWeek(),1L), patternDate));

// 本周最后一天:2017-12-30
System.out.println("本周最后一天: " + format(now.with(WeekFields.of(Locale.CHINA).dayOfWeek(),7L), patternDate));

// 本月初第一天:2017-12-01
System.out.println("本月初第一天: " + format(now.with(TemporalAdjusters.firstDayOfMonth()), patternDate));

// 本月最后一天:2017-12-31
System.out.println("本月最后一天: " + format(now.with(TemporalAdjusters.lastDayOfMonth()), patternDate));

// 本年最后一天:2017-01-01
System.out.println("本年最后一天: " + format(now.with(TemporalAdjusters.firstDayOfYear()), patternDate));

// 本年最后一天:2017-12-31
System.out.println("本年最后一天: " + format(now.with(TemporalAdjusters.lastDayOfYear()), patternDate));

Optional类说明

Optional类的Javadoc描述如下:
这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional基础对象处理

示例代码

// 有则返回, 无则由函数产生
System.out.println(Optional.ofNullable(null).orElseGet(() -> Arrays.asList(1,2,3)));

// 元素存在输出true,反之输出false
System.out.println(Optional.ofNullable("Elon").isPresent());

// 不为空时输出元素,反之输出“默认值”
System.out.println(Optional.ofNullable("Elon").orElse("默认值"));

// 元素存在输出元素,反之抛出异常
System.out.println(Optional.ofNullable("Elon").orElseThrow(IllegalArgumentException::new));


// 元素存在输出true,反之输出false
System.out.println(Optional.ofNullable(null).isPresent());

// 不为空时输出元素,反之输出“默认值”
System.out.println(Optional.ofNullable(null).orElse("默认值"));

// 元素存在输出元素,反之抛出异常
System.out.println(Optional.ofNullable(null).orElseThrow(IllegalArgumentException::new));

示例输出

[1, 2, 3]
true
Elon
Elon
false
默认值

java.lang.IllegalArgumentException
    at java.util.Optional.orElseThrow(Optional.java:290)
    ...

Optional基础集合处理

示例代码

List<Integer> list = Arrays.asList(1, 2, 3, 2, 5, 3);

// 集合不为空的时候进行遍历去重,反之输出空集合
System.out.println(Optional.ofNullable(list).orElse(Lists.newArrayList()).stream().distinct().collect(Collectors.toList()));

// 集合不为空的时候进行遍历去重,反之抛出异常
System.out.println(Optional.ofNullable(list).orElseThrow(IllegalArgumentException::new).stream().distinct().collect(Collectors.toList()));

list = null;

// 集合不为空的时候进行遍历去重,反之输出空集合
System.out.println(Optional.ofNullable(list).orElse(Lists.newArrayList()).stream().distinct().collect(Collectors.toList()));

// 集合不为空的时候进行遍历去重,反之抛出异常 IllegalArgumentException
System.out.println(Optional.ofNullable(list).orElseThrow(IllegalArgumentException::new).stream().distinct().collect(Collectors.toList()));

示例输出

[1, 2, 3, 5]
[1, 2, 3, 5]
[]

java.lang.IllegalArgumentException
    at java.util.Optional.orElseThrow(Optional.java:290)
    ...

Optional复杂集合处理

示例代码

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
class Person{

   private String name;
   private int age;

   public String toString(){
       return JSON.toJSONString(this);
   }
}

@Test
public void list(){
   Person person = null;
   System.out.println(Optional.ofNullable(person).map(x -> x.getName()).orElse("默认姓名"));
   System.out.println(Optional.ofNullable(person).map(x -> x.getAge()).orElse(18));

   List<Person> list = Arrays.asList(new Person("p1", 10), new Person("p2", 15));

   System.out.println("最大年龄用户:" + Optional.ofNullable(list).orElseThrow(NullPointerException:: new).stream().collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge))).get());
   System.out.println("最大年龄数值:" + Optional.ofNullable(list).orElseThrow(NullPointerException:: new).stream().collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge))).get().getAge());
   System.out.println("年龄均值数值:" + Optional.ofNullable(list).orElseThrow(NullPointerException:: new).stream().collect(Collectors.averagingInt(Person::getAge)));
}

示例输出

默认姓名
18
最大年龄用户:{"age":15,"name":"p2"}
最大年龄数值:15
年龄均值数值:12.5

Nashorn JavaScript引擎

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
// jdk.nashorn.api.scripting.NashornScriptEngine
System.out.println( engine.getClass().getName() );
// Result:2.0
System.out.println("Result:" + engine.eval("function f() { return 1; }; f() + 1;"));

Base64支持

final String text = "Base64 finally in Java 8!";
final String encoded = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
final String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
System.out.println(decoded);

Java8新特性示例图

[图片上传失败...(image-672dc3-1576724390193)]

上一篇下一篇

猜你喜欢

热点阅读