当前位置: 首页 > news >正文

Java8部分新特性

一,接口的新特性

  1. 增加default关键字和static关键字修饰接口中的方法。
  2. default方法需要实例引用,static方法只能接口来引用。
  3. 接口里的静态方法不会被继承,静态变量会被继承。
  4. 如果一个类实现了多个接口,并且这些接口相互之间没有继承关系,同时存在存在相同的默认方法。若果多个接口有继承关系,那么,多个接口会被子接口覆盖。
  5. 多个继承中,相同的默认方法,可以在实现类中,重写接口的方法,在重写的方法中使用super关键字调用父接口的方法。
  6. 如果一个接口只有一个抽象方法(包括继承的),那么,该接口默认是一个函数式接口。
  7. 如果接口里面使用FunctionalInterface注解,那么,限定接口里面必须有且只能有一个抽象方法。

demo

定义两个含有default方法和static接口,一个子,一个父

Interface1

// 接口1
public interface Interface1 extends Interface2 {
    // default关键字方法
    default void default1() {
        System.out.println("Interface1的default1方法");
    }
    default void default3() {
        System.out.println("Interface1的default3方法");
    }
    // static关键字方法
    static void static1() {
        System.out.println("Interface1的static1方法");
    }
}

Interface2

// 接口2
public interface Interface2 {
    // default关键字方法
    default void default2() {
        System.out.println("Interface2的default1方法");
    }
    default void default3() {
        System.out.println("Interface2的default3方法");
    }
    // static关键字方法
    static void static2() {
        System.out.println("Interface2的static1方法");
    }
}

定义一个类实现这两个接口

InterfaceImpl

public class InterfaceImpl implements Interface1,Interface2 {

    // 重写父接口的默认方法
    public void defaul3(){
        Interface1.super.default3();
    }
}

测试

public class InterfaceFeatures {
    // 测试方法
    public static void main(String[] args) {
        // 调用接口的静态方法
        Interface1.static1();
        Interface2.static2();
        // 实例一个对象
        InterfaceImpl ii1 = new InterfaceImpl();
        ii1.default1();
        //ii1.static1();
        ii1.default3();

    }
}

使用注解声明的函数式接口

// 函数式接口
@FunctionalInterface
public interface FunctionalInterface1 {
    void test1();
    //void test2();//有且只能有一个抽象方法
    default void d1(){

    }
    static void s1(){

    }
}

二, Lambda表达式

Java是面向对象的语言,不能象函数式语言那样嵌套定义方法。Java的匿名内部类只能存在于创建于它的线程中,不能运行在多线程中,无法充分利用多核的硬件优势。

匿名内部类的缺点:语法相对复杂;在调用内部类的上下文中,指引和this的指代容易混淆;类加载和实例创建语法不可避免;不能引用外部的非final对象;不能抽象化控制流程。

对于上述的问题,开发了Java中使用Lambda表达式。

Lambda表达式只能应用于函数式接口。Lambda表达式可以认为是一种特殊的匿名内部类。

1,Lambda语法

([形参列表,不带数据类型]) –> {

         // 执行语句;

         [return …;]

}

2,形参列表的注意事项

如果形参列表是空的,只需要保留()即可;

如果没有返回值,只需要在{}写执行语句即可;

如果接口的抽象方法只有一个形参,()可以省略,只需要参数的名称即可;

如果执行语句只有一行,可以省略{},但是如果有返回值的时候,有点特殊;

形参列表的数据类型自动推断,只要参数名称;

如果函数式接口的方法有返回值,必须要给定返回值,如果执行语句只有一行代码,可以省略大括号,但必须同时省略return;

demo

public class LambdaTest1 {

  public void testLambda(UserTest4 ut1, int a) {
    int b = ut1.test(a);
    System.out.println("Lambda表达式的返回值是:" + b);
  }

  public static void main(String[] args) {
    // 使用匿名内部类的方式
    UserTest1 ut1 =
        new UserTest1() {
          @Override
          public void test() {
            System.out.println("使用匿名内部类的方式实现接口");
          }
        };
    ut1.test();
    // 使用lambda表达式的方式
    UserTest1 ut2 =
        () -> {
          System.out.println("使用lambda表达式的方式实现接口");
        };
    ut2.test();
    // 无参时,如果执行语句只有一行,可以省略{}和一个;
    // 如果有返回值,可以省略return
    UserTest1 ut3 = () -> System.out.println("简化版,使用lambda表达式的方式实现接口");
    ut3.test();

    // 一个参数,无返回值
    // 数据类型自动根据接口方法中的参数类型定义推断
    UserTest2 ut4 =
        (x) -> {
          System.out.println("一行代码,一个参数,参数值为:" + x);
        };
    ut4.test(5);
    // 简化版
    UserTest2 ut5 = x -> System.out.println("简化版,一行代码,一个参数,参数值为:" + x);
    ut5.test(15);

    // 两个参数,无返回值
    UserTest3 ut6 =
        (x, y) -> {
          System.out.println("两个参数,无返回值。x:" + x + ";y:" + y);
        };
    ut6.test(1, 3);

    // 一个参数,有返回值
    UserTest4 ut7 =
        x -> {
          x += 10;
          return x;
        };
    System.out.println("一个参数,有返回值,值为:" + ut7.test(10));
    // 简化版,一个参数,有返回值,省略{},需要同时省略掉return关键字
    UserTest4 ut8 = x -> x + 10;
    System.out.println("简化版,一个参数,有返回值,值为:" + ut8.test(20));

    // 测试方法中以函数式接口为参数的Lambda表达式语法
    LambdaTest1 lt1 = new LambdaTest1();
    int b = 10;
    lt1.testLambda((a)-> {return a + b;}, 10);
  }
}

// 接口方法无参,无返回值
@FunctionalInterface
interface UserTest1 {
  void test();
}
// 接口方法一个参数,无返回值
@FunctionalInterface
interface UserTest2 {
  void test(int a);
}
// 接口方法两个参数,无返回值
@FunctionalInterface
interface UserTest3 {
  void test(int a, int b);
}
// 接口方法一个参数,一个返回值
@FunctionalInterface
interface UserTest4 {
  int test(int a);
}

三,方法的应用

引用实例方法,自动把调用方法的时候的参数,全部传给引用的方法。

<函数式接口><变量名> = <实例>::<实例方法名>;

//自动把[实参]全部传递引用的实例方法。

<变量名>.<接口方法名>([实参])

引用类方法

全部参数传给引用的方法

<函数式接口><变量名>=<类>::<类方法名>;

//自动把[实参]全部传递给引用的类方法。

<变量名>.<接口方法名>([实参]);

引用类的实例方法

定义、调用接口方法的时候,需要多一个参数,并且参数的类型和引用实例方法的类型必须一致。

把第一个参数作为引用的实例,后面的每个参数全部传递给引用的方法。

interface <函数式接口>

{

         <返回值><方法名>(<类名><名称>[,其他参数…]);

}

<函数式接口><变量名>=<类名>::<实例方法名>;

<变量名>.<方法名>(<类名的实例>[,其他参数]);

构造器引用

把方法的所有参数全部传递给引用的构造器,根据参数的类型推断调用的构造器。

<类名>::new

demo

public class LambdaTest2 {
  public static void main(String[] args) {
    // 实现了方法,然后引用
    MethodRef1 mr1 =
        (s) -> {
          System.out.println(s);
        };
    mr1.test("打印字符串");
    // 实例的实例方法的引用
    MethodRef1 mr2 = System.out::println;
    mr2.test("使用方法的引用");
    // 类的方法的引用
    MethodRef2 mr3 = Arrays::sort;
    int[] array = {1, 55, 23, 2, 5, 16};
    mr3.test(array);
    System.out.println(Arrays.toString(array));
    // 类的实例方法的引用
    MethodRef3 mr4 = PrintStream::println;
    // 第二个参数作为引用的方法的参数
    mr4.test(System.out, "第二个参数");
    // 构造器的引用,根据函数式接口的方法名来推断引用哪个构造器
    MethodRef4 mr5 = String::new;
    String str = mr5.test(new char[] {'h', 'e', 'l', 'l', 'o'});
    System.out.println(str);
    // 上述构造器引用,等价于Lambda表达式的写法为
    MethodRef4 mr6 = (c) -> {
        String s = new String(c);
        return s;
    };
    String str2 = mr6.test(new char[]{'1','b','c'});
    System.out.println(str2);
  }
}

interface MethodRef1 {
  void test(String s);
}

interface MethodRef2 {
  void test(int[] array);
}

interface MethodRef3 {
  void test(PrintStream printStream, String str);
}

interface MethodRef4 {
  String test(char[] chars);
}

四,新的数据流接口

1,stream接口

Stream是Java8中被定义为泛型接口;代表数据流;不是一个数据结构 ,不直接存储数据;通过管道操作数据。

管道代表一个操作序列。包含有,数据集,可能是集合、数组等;0个或多个中间业务,如过滤器;一个终端操作,如forEach。过滤器是,用给定的条件在源数据基础上过滤出新的数据,并 返回一个Stream对象,过滤器包含匹配的谓词。

demo

编写一个Person类

 

public class Person {
    public static enum Sex{
        MALE,FEMALE;
    }
    private String name;
    private int age;
    private Sex gender;
    private double height;

    public Person(String name, int age, Sex gender, double height) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Sex getGender() {
        return gender;
    }

    public void setGender(Sex gender) {
        this.gender = gender;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                ", height=" + height +
                '}';
    }
}

编写一个测试类,测试Stream

public class StreamTest1 {
  public static void main(String[] args) {
    List<Person> personList = createPerson();
    // 获取Stream流
    Stream<Person> personStream = personList.stream();
    personStream.forEach(
        person -> {
          System.out.println(person);
        });
    System.out.println("===========================================");
    // 测试过滤器
    Stream<Person> personStream1 = personList.stream().filter(person -> {
        // 返回性别为女的对象
        return person.getGender() == Person.Sex.FEMALE;
    });
    personStream1.forEach(
        person -> {
          System.out.println(person);
        });
  }

  public static List<Person> createPerson() {
    List<Person> personList = new ArrayList<>();
    Person p1 = new Person("张三", 24, Person.Sex.MALE, 170);
    Person p2 = new Person("李四", 25, Person.Sex.FEMALE, 169);
    Person p3 = new Person("张子怡", 35, Person.Sex.FEMALE, 168);
    Person p4 = new Person("李冰冰", 32, Person.Sex.FEMALE, 171);
    personList.add(p1);
    personList.add(p2);
    personList.add(p3);
    personList.add(p4);
    return personList;
  }
}

2,DoubleStream接口

表示元素类型是double的数据源。

常用方法

max().getAsDouble(),获取数据流中数据集的最大值。

stream.min().getAsDouble(),获取流中数据集的最小值。

stream.average(),获取流中数据集的平均值。

demo

public class StreamTest2 {
  public static void main(String[] args) {
    // 使用DoubleStream获取名字中包含张的平均身高
    List<Person> personList = createPerson();
    double avgHeight = personList
            .stream()
            .filter(
                    person ->
                    {return person.getName().indexOf("张") >= 0;})
            .mapToDouble(person -> {return person.getHeight();})
            .average()
            .getAsDouble();
    System.out.println("姓名中包含张字的人的平均身高为:" + avgHeight);
  }

  public static List<Person> createPerson() {
    List<Person> personList = new ArrayList<>();
    Person p1 = new Person("张三", 24, Person.Sex.MALE, 170);
    Person p2 = new Person("李四", 25, Person.Sex.FEMALE, 169);
    Person p3 = new Person("张子怡", 35, Person.Sex.FEMALE, 168);
    Person p4 = new Person("李冰冰", 32, Person.Sex.FEMALE, 171);
    personList.add(p1);
    personList.add(p2);
    personList.add(p3);
    personList.add(p4);
    return personList;
  }
}

五,日期相关的新的类

1,LocalDate

使用ISO日历表示年月日。

LocalDaet.now(),获取系统当前日期。

LocalDate.of(int year,int month,int dayOfMonth),按指定日期创建LocalDate对象。

getYear(),返回日期中的年份。

getMonth(),返回日期中的月份。

getDayOfMonth(),返回月份中的日。

demo

public class LocalDateTest {
  public static void main(String[] args) {
    // 获取当前日期
    LocalDate date = LocalDate.now();
    // 打印当前日期
    System.out.println(date.getYear() + "-" + date.getMonthValue() + "-" + date.getDayOfMonth() + "\t");
    System.out.println(date.toString());
  }
}

2,LocalTime

用于表示一天中的时间。

LocalTime.now(),获取系统当前时间。

LocalTime.of(int hour, int minute, int seond),按指定时间创建LocalTime对象。

getHour(),返回小时。

getMinute(),返回分钟。

getSecond(),返回秒。

demo

public class LocalTimeTest {
  public static void main(String[] args) {
    // 获取当前时间
    LocalTime time = LocalTime.now();
    // 打印当前时间
    System.out.println(time.getHour() + ":" + time.getMinute() + ":" + time.getSecond());
    System.out.println(time.toString());
  }
}

3,LocalDateTime

用于表示日期和时间。

demo

public class LocalDateTimeTest {
  public static void main(String[] args) {
    // 获取当前日期时间
    LocalDateTime dateTime = LocalDateTime.now();
    // 打印当前日期时间
    System.out.println(
        dateTime.getYear()
            + "年"
            + dateTime.getMonthValue()
            + "月"
            + dateTime.getDayOfMonth()
            + "日\t"
            + dateTime.getHour()
            + "时"
            + dateTime.getMinute()
            + "分"
            + dateTime.getSecond()
            + "秒");
    System.out.println(dateTime.toString());
  }
}

4,DateTimeFormatter

用于将字符串解析为日期。

demo

public class DateTimeFormatterTest {
  public static void main(String[] args) {
    // 按照一定的时间日期格式获取一个格式化对象
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    // 需要格式化的字符串
    String dateTimeStr = "2018年12月23日 17:15:12";
    // 格式化字符串
    LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, dateTimeFormatter);
    System.out.println(dateTime);
  }
}

5,ZonedDateTime

处理日期和时间与相应的时区。

demo

public class ZonedDateTimeTest {
  public static void main(String[] args) {
    // 获取当前时区时间日期
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    // 获取一个指定时间日期格式的格式化对象
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
    // 格式化时间日期为字符串
    String dateTimeStr = zonedDateTime.format(dateTimeFormatter);
    System.out.println(dateTimeStr);
  }
}

 

相关文章:

  • jvm简介
  • mybatis使用foreach处理List中的Map
  • log4j2的配置文件
  • 一个用java的NIO实现的socket的客户端和服务端的demo
  • 使用java的nio的pipe实现两个线程间传送数据的demo
  • org.hibernate.TransactionException: nested transactions not supported异常
  • elasticsearch
  • rancher简介
  • InfluxDB+cAdvisor+Grafana容器管理
  • serviceComb[No schema defined for start.servicecomb.io:]异常
  • ServiceComb
  • kubernetes
  • 生产报redis连接满的问题
  • 一、Linux入门简述
  • 二、Linux入门之文件管理及相关命令
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 2017年终总结、随想
  • C++入门教程(10):for 语句
  • Cookie 在前端中的实践
  • Date型的使用
  • JAVA之继承和多态
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • Python实现BT种子转化为磁力链接【实战】
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • Theano - 导数
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 来,膜拜下android roadmap,强大的执行力
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 我是如何设计 Upload 上传组件的
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 做一名精致的JavaScripter 01:JavaScript简介
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #NOIP 2014# day.2 T2 寻找道路
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (LeetCode 49)Anagrams
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (翻译)terry crowley: 写给程序员
  • (附源码)php新闻发布平台 毕业设计 141646
  • (四)Android布局类型(线性布局LinearLayout)
  • (转)VC++中ondraw在什么时候调用的
  • .NET CLR基本术语
  • .Net Core 中间件验签
  • .Net6 Api Swagger配置
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • .NET中 MVC 工厂模式浅析
  • .NET中的十进制浮点类型,徐汇区网站设计
  • .vue文件怎么使用_我在项目中是这样配置Vue的
  • @Async注解的坑,小心
  • @synthesize和@dynamic分别有什么作用?
  • [AHOI2009]中国象棋 DP,递推,组合数
  • [AIGC codze] Kafka 的 rebalance 机制
  • [AIGC] Redis基础命令集详细介绍
  • [BIZ] - 1.金融交易系统特点