Java8新特性(全)

Java8新特性

  • Lambda表达式
  • 方法引用
  • 函数式接口
  • 默认方法
  • Stream API
  • Optional 类
  • Nashorn JavaScript
  • 新时间日期API
  • Base64

Lambda表达式

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
ambda 表达式的语法格式如下:
(parameters) -> expression
或
(parameters) ->{ statements; }
以下是lambda表达式的重要特征:

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

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)
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 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
        
      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
        
      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);
        
      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }
    
   interface MathOperation {
      int operation(int a, int b);
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
    
   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}

方法引用

方法引用通过方法的名字来指向一个方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号 :: 。
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
 
class Car {
    //Supplier是jdk1.8的接口,这里和lamda一起使用了
    public static Car create(final Supplier<Car> 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());
    }
}

构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:

final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );

静态方法引用:它的语法是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 );

方法引用实例

public class Java8Tester {
   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);
   }
}

函数式接口

定义:
一个接口有且只有一个抽象方法。
函数式接口的实例可以通过 lambda 表达式、方法引用或者构造方法引用来创建。

1.如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口
函数式接口应满足:
该接口是一个接口类型而不是注解类型,枚举类型或类类型
被声明 @FunctionalInterface 注解的接口应该满足函数式接口的定义

2.如果某个接口只有一个抽象方法,但我们并没有给该接口声明 @FunctionalInterface 注解,那么编译器依旧会将该接口看作是函数式接口

默认方法

简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。
目的是为了解决接口的修改与现有的实现不兼容的问题。

public class Car implements Vehicle, FourWheeler {
   default void print(){
      System.out.println("我是一辆四轮汽车!");
   }
}

Stream API

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

在 Java 8 中, 集合接口有两个方法来生成流:

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

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

Stream流有一些特性:

Stream流不是一种数据结构,不保存数据,它只是在原数据集上定义了一组操作。
这些操作是惰性的,即每当访问到流中的一个元素,才会在此元素上执行这一系列操作。
Stream不保存数据,故每个Stream流只能使用一次。

原文链接:https://blog.csdn.net/lixiaobuaa/article/details/81099838

一、 流的生成方法
Collection接口的stream()或parallelStream()方法
静态的Stream.of()、Stream.empty()方法
Arrays.stream(array, from, to)
静态的Stream.generate()方法生成无限流,接受一个不包含引元的函数
静态的Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数
Pattern接口的splitAsStream(input)方法
静态的Files.lines(path)、Files.lines(path, charSet)方法
静态的Stream.concat()方法将两个流连接起来

二、流的Intermediate方法(中间操作)
filter(Predicate)
将结果为false的元素过滤掉
map(fun)
转换元素的值,可以用方法引元或者lambda表达式
flatMap(fun)
若元素是流,将流摊平为正常元素,再进行元素转换
limit(n)
保留前n个元素
skip(n)
跳过前n个元素
distinct()
剔除重复元素
sorted()
将Comparable元素的流排序
sorted(Comparator)
将流元素按Comparator排序
peek(fun)
流不变,但会把每个元素传入fun执行,可以用作调试

三、流的Terminal方法(终结操作)
约简操作
max(Comparator)
min(Comparator)
count()
findFirst()
返回第一个元素
findAny()
返回任意元素
anyMatch(Predicate)
任意元素匹配时返回true
allMatch(Predicate)
所有元素匹配时返回true
noneMatch(Predicate)
没有元素匹配时返回true
reduce(fun)
从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数
reduce(a, fun)
a为幺元值,作为累积器的起点
reduce(a, fun1, fun2)
与二元变形类似,并发操作中,当累积器的第一个参数与第二个参数都为流元素类型时,可以对各个中间结果也应用累积器进行合并,但是当累积器的第一个参数不是流元素类型而是类型T的时候,各个中间结果也为类型T,需要fun2来将各个中间结果进行合并

收集操作
iterator()
forEach(fun)
forEachOrdered(fun)
可以应用在并行流上以保持元素顺序
toArray()
toArray(T[] :: new)
返回正确的元素类型
collect(Collector)
collect(fun1, fun2, fun3)
fun1转换流元素;fun2为累积器,将fun1的转换结果累积起来;fun3为组合器,将并行处理过程中累积器的各个结果组合起来

然后再看一下有哪些Collector收集器:

Collectors.toList()
Collectors.toSet()
Collectors.toCollection(集合的构造器引用)
Collectors.joining()、Collectors.joining(delimiter)、Collectors.joining(delimiter、prefix、suffix)
字符串元素连接
Collectors.summarizingInt/Long/Double(ToInt/Long/DoubleFunction)
产生Int/Long/DoubleSummaryStatistics对象,它有getCount、getSum、getMax、getMin方法,注意在没有元素时,getMax和getMin返回Integer/Long/Double.MAX/MIN_VALUE
Collectors.toMap(fun1, fun2)/toConcurrentMap
两个fun用来产生键和值,若值为元素本身,则fun2为Function.identity()
Collectors.toMap(fun1, fun2, fun3)/toConcurrentMap
fun3用于解决键冲突,例如(oldValue, newValue) -> oldValue,有冲突时保留原值
Collectors.toMap(fun1, fun2, fun3, fun4)/toConcurrentMap
默认返回HashMap或ConcurrentHashMap,fun4可以指定返回的Map类型,为对应的构造器引元
Collectors.groupingBy(fun)/groupingByConcurrent(fun)
fun是分类函数,生成Map,键是fun函数结果,值是具有相同fun函数结果元素的列表
Collectors.partitioningBy(fun)
键是true/false,当fun是断言函数时用此方法,比groupingBy(fun)更高效
Collectors.groupingBy(fun1, fun2)
fun2为下游收集器,可以将列表转换成其他形式,例如toSet()、counting()、summingInt/Long/Double(fun)、maxBy(Comparator)、minBy(Comparator)、mapping(fun1, fun2)(fun1为转换函数,fun2为下游收集器)

Optional 类

Optional 类致力于解决null安全问题的一个API。
善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅

在这里插入图片描述
通过链式调用优雅的解决null的问题
在这里插入图片描述

Nashorn JavaScript

Nashorn 一个 javascript 引擎。

从JDK 1.8开始,Nashorn取代Rhino(JDK 1.6, JDK1.7)成为Java的嵌入式JavaScript引擎。Nashorn完全支持ECMAScript 5.1规范以及一些扩展。它使用基于JSR 292的新语言特性,其中包含在JDK 7中引入的 invokedynamic,将JavaScript编译成Java字节码。

与先前的Rhino实现相比,这带来了2到10倍的性能提升。

时间API

 * 之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum
 * java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。
 * java.util.Date是一个“万能接口”,它包含日期、时间,还有毫秒数,更加明确需求取舍
 * 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对。
表示日期的LocalDate
表示时间的LocalTime
表示日期时间的LocalDateTime
在旧版的日期时间API中:
非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的。
时区处理麻烦 − 日期类并不提供国际化,没有时区支持
Java8:
Local(本地) − 简化了日期时间的处理,没有时区的问题。
Zoned(时区) − 通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,
时刻(instants),过程(during)与时钟(clock)的操作。

本地化日期时间 API

public class TimeApiTest {

    public static void main(String[] args) {
        //本地化日期API
        LocalDateTime currentTime = LocalDateTime.now();
        System.out.println(currentTime);
        LocalDate localDate = currentTime.toLocalDate();
        System.out.println(localDate);
        Month month = currentTime.getMonth();
        int day = currentTime.getDayOfMonth();
        int seconds = currentTime.getSecond();
        System.out.println("月: " + month + ", 日: " + day + ", 秒: " + seconds);
        LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
        System.out.println("date2: " + date2);
        // 12 december 2014
        LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
        System.out.println("date3: " + date3);
        // 22 小时 15 分钟
        LocalTime date4 = LocalTime.of(22, 15);
        System.out.println("date4: " + date4);
        // 解析字符串
        LocalTime date5 = LocalTime.parse("20:15:30");
        System.out.println("date5: " + date5);
    }
}

使用时区的日期时间API

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);
        
      ZoneId id = ZoneId.of("Europe/Paris");
      System.out.println("ZoneId: " + id);
        
      ZoneId currentZone = ZoneId.systemDefault();
      System.out.println("当期时区: " + currentZone);
   }
}

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’作为分割。编码输出最后没有行分割。
url有规范,在参数值中出现&字符会截断参数
url中文的问题,编码客转换为英文
也是第一种情况,url中有个参数值是url,传输的时候会出现错误
 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("runoob?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());
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值