java8的常用新特性

改动

  • hashmap的存储方式

java8在hashmap的链表长度达到8时,就会自动转换为红黑树进行存储。

可以参考一下这个HashMap与HashTable与并发容器

  • 接口中可以有非抽象的方法

  接口中可以有两种有方法体的方法
  1.static修饰的方法
       接口被继承时,static修饰的有方法体的方法不会被继承
       接口被实现时,static修饰的有方法体的方法与实现类无关,不能被重写
       该方法只能被自身调用,通过类名来引用,继承或实现的都不行
  2.default修饰的方法
       接口被继承时,default修饰的有方法体的方法可以被继承并重写
       接口被实现时,default修饰的有方法体的方法可以被实现类重写
       该方法可以被继承或实现类引用
 

public interface FirstInterface {

    //接口中的成员变量默认是静态常量
    String STRING = "First Interface";

    static void funStatic(){
        System.out.println(STRING + " : I am the static method!");
    }

    default void funDefault(){
        System.out.println(STRING + " : I am the default method!");
    }

    void fun();
}

/**
 * 继承第一个接口
 */
public interface SecondInterface extends FirstInterface{

    String STRING = "Second Interface";

    //无法重写第一个接口的static方法
    static void funStatic(){
        System.out.println(STRING + " : I am the static method!");
    }

    //可以重写第一个接口的default方法
    @Override
    default void funDefault(){
        System.out.println(STRING + " : I am the default method!");
    }

    //普通方法可以被重写,emmmm并没有什么用,又没有方法体
    @Override
    void fun();
}

//重写default
public class ImplementFirst implements FirstInterface{

    @Override
    public void funDefault() {
        System.out.println("I have implement the First Interface!");
    }

    @Override
    public void fun() {
        System.out.println("I have implement the First Interface!");
    }
}

//不重写default
public class ImplementSecond implements SecondInterface{

    @Override
    public void fun() {
        System.out.println("I have implement the Second Interface!");
    }
}

public class Main {

    public static void main(String[] args){
        FirstInterface firstInterface = new ImplementFirst();
        //无法调用static方法
        //无法调用STRING常量
        firstInterface.fun();
        //重写的
        firstInterface.funDefault();

        SecondInterface secondInterface = new ImplementSecond();
        secondInterface.fun();
        //没有重写的
        secondInterface.funDefault();

        //通过自身调用
        FirstInterface.funStatic();
        System.out.println(FirstInterface.STRING);
    }

}

输出:
I have implement the First Interface!
I have implement the First Interface!
I have implement the Second Interface!
Second Interface : I am the default method!
First Interface : I am the static method!
First Interface

新增

  • Lambda表达式
  基本语法:
      <函数式接口>  <变量名> = (参数1,参数2...) -> {
           方法体
      }
 
  引用实例方法:
      <函数式接口>  <变量名> = <实例>::<实例方法名>
      调用:
      <变量名>.接口方法([实际参数...])
 
  引用类方法:
      <函数式接口>  <变量名> = <类>::<类方法名称>
      调用:
      <变量名>.接口方法([实际参数...])
 
  引用类的实例方法:
      定义接口
      interface <函数式接口>{
          <返回值> <方法名>(<类><类名称>,[其他参数...]);
      }
      <函数式接口>  <变量名> = <类>::<类实例方法名>
      调用:
      <变量名>.接口方法(类的实例,[实际参数...])
 
  引用构造器方法:
      <函数式接口>  <变量名> = <类>::<new>
      调用:
      <变量名>.接口方法([实际参数...])
public class Lambda {

    //无参,无返回值
    private interface NoReturn{
        void foo();
    }

    //无参,有返回值
    private interface AReturn{
        int foo();
    }

    //有参,无返回值
    private interface NoReturnParam{
        void foo(int a);
    }

    //有参,有返回值
    private interface AReturnParam{
        int foo(int a);
    }
    
    public static void main(String[] args){
        //无参,无返回值
        //旧的实现方式,此处显示的为实现接口中方法
        NoReturn noReturn = new NoReturn() {
            @Override
            public void foo() {
                System.out.println("hello old");
            }
        };
        noReturn.foo();
        //Lambda表达式,此处显示的为重写接口中的方法
        NoReturn noReturn1 = () -> System.out.println("hello lambda");
        noReturn1.foo();

        //无参,有返回值
        int y = 0;
        AReturn aReturn = () -> {
            System.out.println("the y will be final:" + y);
            return y + 10;
        };
        //此处使用y会有异常,y在return之后变成了final,在内部可以进行改变
        System.out.println(aReturn.foo());

        //有参,无返回值
        NoReturnParam NoReturnParam = (a) -> System.out.println(a);
        NoReturnParam NoReturnParam1 = b -> System.out.println(b);
        NoReturnParam.foo(1);
        NoReturnParam1.foo(2);
        //上面2中方式的更简单表达
        NoReturnParam NoReturnParam3 = System.out::println;
        NoReturnParam3.foo(3);
        
        //有参,有返回值
        AReturnParam aReturnParam = a -> {
            System.out.println(a);
            return a % 10;
        };
        System.out.println(aReturnParam.foo(66));
    }
}

输出:
hello old
hello lambda
the y will be final:0
10
1
2
3
66
6

总结:有返回值的应该只能使用箭头的方式,无返回值的可以使用箭头,也可以使用双冒号。箭头的方式可以写多行代码,双冒号的应该只能写一行的。

  •   Predicate 接口

       Predicate 接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)
 

  •   Function 接口

       Function 接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen)
 

  •   Consumer 接口

       Consumer 接口表示执行在单个参数上的操作。接口只有一个参数,且无返回值
 

  •   Comparator 接口

       Comparator 是老Java中的经典接口, Java 8在此之上添加了多种默认方法
 

  •   Supplier 接口

       Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数
 

  •   Optional 接口

       Optional 不是函数是接口,这是个用来防止NullPointerException异常的辅助类型,这是下一届中将要用到的重要概念,现在先简单的看看这个接口能干什么:
       Optional 被定义为一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8中,不推荐你返回null而是返回Optional。
 

  •   Stream 接口
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class NewStream {

    private static void createStream(){
        //通过Stream.of来创建
        Stream<Integer> integerStream = Stream.of(1,2,4,8);
        Stream<String> stringStream = Stream.of("hello");

        //通过Stream.generate来创建,创建的是无限长度的Stream,三种一样,写法不同
        //由于生成的长度无限,所以采用的懒加载,并且一般与limit配合使用,如第3个
        Stream.generate(new Supplier<Double>() {
            @Override
            public Double get() {
                return Math.random();
            }
        });
        Stream<Double> doubleStream1 = Stream.generate(() -> Math.random());
        Stream<Double> doubleStream2 = Stream.generate(Math::random).limit(10);

        //通过Stream.iterate来创建,也是生成无限长度的Stream,其元素的生成是重复对给定的种子值(seed)调用用户指定函数来生成的
        //也要配合limit使用,取出前10个数字打印
        Stream.iterate(46, i -> i + 1).limit(10).forEach(System.out::println);

        //Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。
        //Java 8扩展了集合类,可以通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个Stream。
        //Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
        int max = 1000000;
        List<String> list = new ArrayList<>(max);
        for (int i = 0; i < max; i++){
            list.add(UUID.randomUUID().toString().replaceAll("-", ""));
        }
        //串行排序
        long t0 = System.nanoTime();
        long count = list.stream().sorted().count();
        System.out.println(count);
        long t1 = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
        System.out.println(String.format("sequential sort took: %d ms", millis));
        //并行排序
        long t2 = System.nanoTime();
        long count1 = list.parallelStream().sorted().count();
        System.out.println(count1);
        long t3 = System.nanoTime();
        long millis1 = TimeUnit.NANOSECONDS.toMillis(t3 - t2);
        System.out.println(String.format("parallel sort took: %d ms", millis1));

        //长度为18,大于50的有8个数
        List<Integer> integerList = Arrays.asList(8, 25, 91, 35, 74, 0, 27, 36, 95, 59, 19, 22, 4, 25, 59, 84, 82, 66);
        //count方法,统计stream的长度
        System.out.println("count:" + integerList.parallelStream().count());

        //max方法,获取最大值,调用Comparator接口
        System.out.println("max:" + integerList.parallelStream().max(Comparator.comparingInt(a -> a)).get());

        //min方法,获取最小值,调用Comparator接口
        System.out.println("min:" + integerList.parallelStream().min(Comparator.comparingInt(a -> a)).get());

        //filter方法,通过一个predicate接口来过滤并只保留符合条件的元素,中间操作
        System.out.println("count filter > 50:" + integerList.stream().filter(Objects::nonNull).filter(num -> num > 50).count());

        //distinct方法,去除stream中的重复元素,中间操作
        integerList.stream().distinct().forEach(System.out::println);
        System.out.println("after distinct:" + integerList.toString());

        //sorted方法,排序stream,可以使用filter,中间操作
        //需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据integerList是不会被修改的
        integerList.stream().sorted().filter(num -> num > 10).forEach(System.out::println);
        System.out.println("after sorted:" + integerList.toString());

        //map方法,根据筛选创建一个新的stream
        //自带mapToInt,mapToLong,mapToDouble方法
        List<String> strings = new ArrayList<>();
        strings.add("123");
        strings.add("312");
        strings.add("231");
        strings.stream().mapToInt(Integer::valueOf).forEach(System.out::println);
        strings.stream().mapToInt(Integer::parseInt).forEach(System.out::println);

        //limit方法,对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素,中间操作
        //skip方法,返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream,中间操作
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(null);
        numbers.add(5);
        numbers.add(5);
        numbers.add(9);
        numbers.add(11);
        System.out.println("sum is:" + numbers.stream().filter(Objects::nonNull).distinct().mapToInt(num -> num * 2).peek(System.out::println).skip(2).limit(4).sum());
        System.out.println("after limit or skip:" + numbers.toString());

        //match匹配,Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。返回一个boolean类型的值,所有的匹配操作都是最终操作
        List<String> stringList = new ArrayList<>();
        stringList.add("hello");
        stringList.add("world");
        stringList.add("i");
        stringList.add("need");
        stringList.add("to");
        stringList.add("improve");
        boolean isMatch = stringList.stream().allMatch(s -> s.startsWith("i"));
        System.out.println("allMatch:" + isMatch);
        System.out.println("anyMatch:" + stringList.stream().anyMatch(s -> s.startsWith("i")));
        System.out.println("noneMatch:" + stringList.stream().noneMatch(s -> s.length() > 9));

        //Reduce 规约,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的,最终操作
        Optional<String> optional = stringList.stream().reduce((s1, s2) -> s1 + s2);
        optional.ifPresent(System.out::println);
    }

    public static void main(String[] args){
        createStream();
    }
}

输出:
46
47
48
49
50
51
52
53
54
55
1000000
sequential sort took: 880 ms
1000000
parallel sort took: 505 ms
count:18
max:95
min:0
count filter > 50:8
8
25
91
35
74
0
27
36
95
59
19
22
4
84
82
66
after distinct:[8, 25, 91, 35, 74, 0, 27, 36, 95, 59, 19, 22, 4, 25, 59, 84, 82, 66]
19
22
25
25
27
35
36
59
59
66
74
82
84
91
95
after sorted:[8, 25, 91, 35, 74, 0, 27, 36, 95, 59, 19, 22, 4, 25, 59, 84, 82, 66]
123
312
231
123
312
231
2
10
18
22
sum is:40
after limit or skip:[1, null, 5, 5, 9, 11]
allMatch:false
anyMatch:true
noneMatch:true
helloworldineedtoimprove

总结:中间操作不会改变原来的数据源,最终操作会改变。


主要参考大佬:JAVA8 十大新特性详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值