Java8的主要新特性

1、对HashMap集合的数据结构优化

原来的HashMap采用的数据结构是哈希表(数组+链表),HashMap默认大小是16,一个下标0-15的数组,往里面存储元素时,首先调用元素的hashcode()方法,计算出哈希值,经过哈希算法找到对应的数组的索引,如果对应索引没有存放元素则直接存放,如果已经有元素了,(发生碰撞,equals方法就是碰撞时才会执行的方法)–那么调用它们的equals方法比较内容(key),如果内容一样,则后面的value值代替前者的value值;如果内容不同,则后加的放在前面,(挂在下面),形成一个链表。

这种情况下,如果链表无限下去,效率极低,碰撞避免不了

1.8之后,在数组+链表+红黑树来实现hashMap,当碰撞的元素个数大于8时或总容量大于64,会有红黑树的引入。

2、Lambda表达式

  • lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码
  • 最直接的优点:简洁代码
  • 只有函数式接口的匿名内部类 才可以使用Lambda表达式来进行简化

函数式接口不同于普通接口,接口中只有一个抽象方法是需要我们去实现的,Lambda表达式正好是针对这个唯一的抽象方法使用

public class TreeSetTest {
    public static void main(String[] args) {
        //创建实现Comparator接口的匿名类对象,对象方法的参数和返回值类型均为Integer类型
        Comparator<Integer> cpt1 = new Comparator<Integer>() {
            //接口里有唯一方法,可以用匿名内部类来创建实现接口的类
            @Override
            public int compare(Integer o1, Integer o2) {
              //Integer中封装了比较大小的方法compare
                return Integer.compare(o1, o2);
            }
        };
/**使用lambda表达式
 *创建实现Comparator接口的类的对象,重写接口的方法
 *(x,y)实现方法参数,Integer.compare(x,y)方法实现
 * 只需要写参数名和方法实现。因为方法名唯一已经知道了
 */
       Comparator<Integer> cpt2 = (x, y) -> Integer.compare(x, y);


        //每插入一条数据,就用比较器来比较一次
      //TreeSet内部元素有序、不可重复
        TreeSet<Integer> set = new TreeSet<>(cpt1);
        set.add(1);
        set.add(3);
        set.add(2);
        set.add(6);
        System.out.println(set);
        System.out.println("=========================");


    }
}

  • 可以自定义一个比较器,通过重写比较器的方法,来自定义比较的字段,如,自定义一个来比较学生的成绩的比较器

        //自己重写Comparator中的compare方法,变成比较学生成绩的比较器
        Comparator<Student>cs = (s1,s2)-> ((s1.grade < s2.grade) ? -1 : (s1.grade == s2.grade) ? 0 : 1);

        TreeSet<Student>treeSet = new TreeSet<>((Comparator) cs);
        treeSet.add(new Student(78));
        treeSet.add(new Student(68));
        treeSet.add(new Student(58));
        treeSet.add(new Student(88));
        for (Student student:treeSet
             ) {
            System.out.println(student);
        }

3、Default关键字

  • 在JDK1.8之前,default一直是switch用于条件分值中默认项的一个关键字。但是在JDK1.8之后,它被赋予了新的功能,它可以被用在接口中,定义非抽象方法。
  • JDK1.8之后,接口中声明的方法就并不一定是抽象方法了 ,现在经过default修饰的方法可以有了方法体了。
interface TestInterface {
    //此处默认会是public static final修饰的,如果你修改,会有错误提示
    String test= "test";
     static void test1(){//此处有方法体
     System.out.println("我是interface中的static修饰的方法体");
	 }
	 default void test2(){ //此处有方法体
        System.out.println("我是interface中的default修饰的方法体");
    }
 }

 public class TestInterface8 implements TestInterface{//一个类实现接口,相当于继承这个方法里的default方法
     public static void  main(String[] args)
	{
        //接口中的方法不一定都是abstract
		 TestInterface8 a=new TestInterface8();
         //继承接口中的default方法test2
		 a.test2();
         //接口里的static方法可以直接类名.方法来调用
		 TestInterface.test1();
    }
}
  • 如上代码,jdk1.8之后,接口中的方法不再都是抽象方法,接口中的方法可以通过 static或者defalut修饰,并且可以拥有方法体。通过static修饰的方法,可以有方法体,实现接口的类,可以直接通过接口类.方法来调用 ;通default修饰的方法,可以有方法体,实现接口的类,可通过创建接口类的对象,通过对象调用default方法

  • 这是JDK8中为了加强接口的能力,使得接口可以存在具体的方法,前提是方法需要被default或static 关键字所修饰。这样做的好处是接口的每个实现类如果都想要相同的功能,就不需要重复代码,而是在接口进行定义即可 。默认方法在子类也可以被重写。

  • interface 的设计初衷是面向抽象,提高扩展性。这也留有一点遗憾,Interface 修改的时候,实现它的类也必须跟着改。于是1.8之后,interface中修改方法,可以加static或default修饰,这样子类不用一定要实现,并且可以直接调用

4、Stream

  • Stream是JDK 8 中最优秀的设计,集合的操作中提供了更加便捷的方式,这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。
  • Stream是对 Java 集合运算和表达的高阶抽象。将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
  • 使用场景:适用于集合操作超过两个步骤 ;任务较重,注重效能,希望并发执行;函数式编程的编码等场景中。Stream 存在于 java.util.stream 包中,

Stream的创建

//通过集合创建
List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();

//通过数组创建
int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);

//通过Stream的静态方法: of(),iterate(),generate()
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);

Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);



遍历/匹配

  List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);

        // 遍历输出符合条件的元素。 遍历输出x>6的元素
        list.stream().filter(x -> x > 6).forEach(System.out::println);
        // 匹配第一个
        Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
        // 是否包含符合特定条件的元素
        boolean anyMatch = list.stream().anyMatch(x -> x > 6);


筛选filter

List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
//筛选大于6的元素并打印出来
 list.stream()
   .filter(x->x>6)
   .forEach(System.out::println);
          
		

5、函数式接口

  • 函数式接口是仅且只能包含一个抽象的方法 的接口,每一个该类型的lambda的表达式都会匹配到这个抽象方法上,jdk1.8提供**@FunctionalInterface**注解来定义函数式接口 ,如:
/**
 * 函数式接口:只包含一个抽象方法的接口,称为函数式接口
 * 通过 Lambda 表达式来创建该接口的对象
 * 可以通过@FunctionalInterface注解检查它是否是一个函数式接口,也可以省略
 */
@FunctionalInterface
interface Haha {
    public int test(int a, int b);
}

public class FunInter {
    public static void main(String[] args) {
/**
 1.调用Haha接口的test方法
 2.该方法用lambda表达式实现test方法
 3.在lambda表达式中(a,b)表示方法的参数,a+b为方法的实现
 */
       Haha haha = (a, b) -> a + b;
       System.out.println(haha.test(2, 5));
      
	   //System.out.println(((Haha)(a, b) -> a + b).test(2, 5));

    }
}

6、方法与构造方法引用

  • jdk1.8提供一种方式,通过::关键字来传递方法或者引用,方法引用分为三种:
    • 静态方法引用,通过类名::静态方法名,如 Integer :: parseInt
    • 实例方法引用,通过实例对象::实例方法,如 str::substring
    • 构造方法引用,通过类名::new ,如User::new
//Integer类
public final class Integer {
    public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
    }
}


//User类
public class User {
    private String username;
    private Integer age;
    public User() {
    }
    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
    // Getter&Setter
} 


/*
三种::引用方式

*/
public static void main(String[] args) {
    // 使用双冒号::来构造静态函数引用 。创建实现Function接口的对象
  //通过类名::静态方法名
    Function<String, Integer> fun = Integer::parseInt;
    Integer value = fun.apply("123");
    System.out.println(value);
 
    // 使用双冒号::来构造非静态函数引用
  //通过 实例对象名::实例方法名  创建实现Function接口的对象
    String content = "Hello JDK8";
    Function<Integer, String> func = content::substring;
    String result = func.apply(1);
    System.out.println(result);
 
    // 构造函数引用
  //通过  类名::new   创建实现 BiFunction接口的对象
    BiFunction<String, Integer, User> biFunction = User::new;
    User user = biFunction.apply("mengday", 28);
    System.out.println(user.toString());
 
    // 函数引用也是一种函数式接口,所以也可以将函数引用作为方法的参数
    sayHello(String::toUpperCase, "hello");
}
 
// 方法有两个参数,一个是
private static void sayHello(Function<String, String> func, String parameter){
    String result = func.apply(parameter);
    System.out.println(result);
}
  • 目前为止,有三种创建函数式接口对象的方式,匿名内部类创建,lambda表达式创建,方法的引用
package day01;


class Person {
    String firstName;
    String lastName;
    Person() {
        System.out.println("Person()被调用");
    }
    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        System.out.println("Person(String firstName, String lastName)被调用");
        System.out.println("firstName =" + firstName);
        System.out.println("lastName =" + lastName);
    }
}

/**
 * PersonFactory接口的方法形参类型为String类型,返回值为Person类型
 */
interface PersonFactory<String, Person> {

    public Person create(String firstName, String lastName);
}

public class PerFa {
    public static void main(String[] args) {
        System.out.println("使用匿名类创建接口的对象");
        PersonFactory<String, Person> personFactory1 = new PersonFactory<String, Person>() {
            @Override
            public Person create(String firstName, String lastName) {
                return new Person(firstName, lastName);
            }
        };
        Person person1 = personFactory1.create("li", "sa");
        System.out.println(person1);
      
      
      
      
        System.out.println("*****************************");
        System.out.println("使用lambda表达式创建接口的对象");
        PersonFactory<String, Person> personFactory2 =
                (firstName, lastName) -> new Person(firstName, lastName);
        Person person2 = personFactory2.create("zhang", "san");
        System.out.println(person2);
      
      
      
      
        System.out.println("*****************************");
        /**
         使用构造方法引用创建接口的对象
         使用 Person::new 来获取Person类构造函数的引用,(new Person)
         Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数
         */
        System.out.println("使用构造方法引用创建接口的对象");
      	//根据接口的方法的参数类型来自动选择合适的构造函数
        PersonFactory<String, Person> personFactory3 = Person::new;
        Person person3 = personFactory3.create("Peter", "Parker");
        System.out.println(person3);

    }
}

7、Date-Time API

  • 这是对java.util.Date强有力的补充,解决了Date类的大部分痛点

非线程安全

时区处理麻烦

各种格式化、和时间计算繁琐

设计有缺陷,Date类同时包含日期和时间;还有一个java.sql.Date,容易混淆

  • java.util.Date 既包含日期又包含时间,而java.time把它们进行了分离。java.time主要类
LocalDateTime.class //日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
LocalDate.class //日期 format: yyyy-MM-dd
LocalTime.class //时间 format: HH:mm:ss
  • 1.8之后的格式化
public void newFormat(){
    //format yyyy-MM-dd  日期
    LocalDate date = LocalDate.now();
    System.out.println(String.format("date format : %s", date));

    //format HH:mm:ss   时间
    LocalTime time = LocalTime.now().withNano(0);
    System.out.println(String.format("time format : %s", time));

    //format yyyy-MM-dd HH:mm:ss  时间+日期
    LocalDateTime dateTime = LocalDateTime.now();
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String dateTimeStr = dateTime.format(dateTimeFormatter);
    System.out.println(String.format("dateTime format : %s", dateTimeStr));
}

  • 1.8之后的字符串转日期格式
LocalDate date = LocalDate.of(2021, 1, 26);
LocalDate.parse("2021-01-26");

LocalDateTime dateTime = LocalDateTime.of(2021, 1, 26, 12, 12, 22);
LocalDateTime.parse("2021-01-26 12:12:22");

LocalTime time = LocalTime.of(12, 12, 22);
LocalTime.parse("12:12:22");

  • 1.8之后获取指定日期
public void getDayNew() {
    LocalDate today = LocalDate.now();
    //获取当前月第一天:
    LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
    // 取本月最后一天
    LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
    //取下一天:
    LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
    //当年最后一天
    LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
    //2021年最后一个周日
    LocalDate lastMondayOf2021 = LocalDate.parse("2021-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
}

  • JDBC和java8

Date----> LocalDate

Time----> LocalTime

Timestamp---->LocalDateTime

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zero摄氏度

感谢鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值