JDK1.8新特性

总结下常见的1.8新特性

JDK1.8最大的改变就是:1.Lambda表达式,2.Stream API

1.接口的扩展方法
jdk1.8之前,接口中只允许有抽象方法,但在1.8之后,接口中允许有多个非抽象的方法,但是必须使用default进行修饰,叫做扩展方法。
其实这么定义一个方法的主要意义是定义一个默认方法,也就是说这个接口的实现类实现了这个接口之后,可以不重写实现类接口的default方法,直接调用default修饰的方法
函数式接口中还可以定义多个static方法

public interface A {
    
    void test1();
    
    public default void test2(){
        System.out.println("新特性");
    }
	
	public static void test3(){
		System.out.print("static")
	}
}

public class B implements A{

    @Override
    public void test1() {
        
    }
    
    public static void main(String[] args) {
        A a = new B();
        a.test2();
        A.test3();
    }

}

2.时间日期的更新
1.8之前JDK自带的日期处理类非常不方便,我们处理的时候经常是使用的第三方工具包,比如commons-lang包等。不过1.8出现之后这个改观了很多,比如日期时间的创建、比较、调整、格式化、时间间隔等。这些类都在java.time包下。比原来实用了很多

LocalDate/LocalTime/LocalDateTime(类似于String类,不可变性,可替换Calendar类)

TemporalAdjusters
//这个类在日期调整时非常有用,比如得到当月的第一天、最后一天,当年的第一天、最后一天,下一周或前一周的某天等。

java.time.Instant (可替换Date类)

DateTimeFormatter(替代SimpleDateFormat类)
//现在1.8引入了DateTimeFormatter类,在使用的时候一般配合LocalDate/LocalTime/LocalDateTime使用,
比如想把当前日期格式化成yyyy-MM-dd hh:mm:ss的形式:
LocalDateTime ldt = LocalDateTime.now();  
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");         
System.out.println(dtf.format(ldt));

3.在HashMap中1.8添加新特性,底层实现为(数组+链表+红黑二叉树)

4.Lambda表达式(不是所有的接口都可以通过这种方法来调用,只有函数式接口才行)
Lambda表达式是jdk1.8里面的一个重要的更新,这意味着java也开始承认了函数式编程,并且尝试引入其中。
“函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!”

		Runnable runnable = () -> System.out.println("我爱中国!");
        runnable.run();

        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱中国!");
            }
        };
        r.run();

        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };

        int compare = comparator.compare(12, 56);
        System.out.println(compare);

        Comparator<Integer> c = (o1,o2) -> Integer.compare(o1,o2);

        int compare1 = c.compare(12,56);
        System.out.println(compare1);

		Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("中国");

        Consumer<String> consumer1 = s -> {
            System.out.println(s);
        };
        consumer1.accept("中国");

函数式接口(lambda表达式,方法引用,构造器引用,数组引用都是函数式接口的实例)
“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。jdk1.8提供了一个@FunctionalInterface注解来定义函数式接口,如果我们定义的接口不符合函数式的规范便会报错。

Java内置的核心函数式接口
消费型接口:Consumer<T>  参数T  返回值void   方法:void accept(T t)
供给型接口:Supplier<T>  参数无  返回值T		方法:T get()
函数型接口:Function<T,R>  参数T   返回值R     方法:R apply(T t)
断定型接口:Predicate<T>   参数T   返回值Boolean   方法  Boolean test(T t)

	//示例:
    @Test
    public void test1(){
    
        //原始的方法调用
        happyTime(200, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("花销"+aDouble+"元");
            }
        });
        //lambda表达式调用
        happyTime(300,money -> System.out.println("花销"+money+"元"));
    }

    public void happyTime(double money, Consumer<Double> consumer){
        consumer.accept(money);
    }
除了Java提供的,我们也可以自定义函数式接口
@FunctionalInterface
public interface MyLambda {
    
    public void test1(String y);

	//这里如果继续加一个抽象方法便会报错
	//public void test1();
    
	//default方法可以任意定义
    default String test2(){
        return "123";
    }
    
    default String test3(){
        return "456";
    }

	//static方法也可以定义
    static void test4(){
        System.out.println("789");
    }
}

//调用
MyLambda myLambda = y -> {
	System.out.println("Hello!");
} 

5.方法引用
使用情景:当要传递给lambda体的操作,已经有实现的方法,就可以使用方法引用
方法引用:本质上就是lambda表达式,而lambda表达式作为函数式接口的实例,所以,方法引用也是函数式接口的实例
使用格式:类/(对象) :: 方法名
具体使用情形:
1.对象::非静态方法
2.类::静态方法
3.类::非静态方法
方法引用使用的要求:函数式接口中的抽象方法的参数,返回值要和方法引用方法的参数,返回值相同(对于情形1,2而言)

	//对象::非静态方法
	//void accept(T t) 
	//void println(T t)
	@Test
    public void test2(){
        Consumer<String> consumer1 = str -> System.out.println(str);
        consumer1.accept("天津");

        PrintStream printStream = System.out;
        Consumer<String> consumer2 = printStream :: println;
        consumer2.accept("北京");
    }
    
	//类::非静态方法
	@Test
    public void test3() {
        Comparator<String> comparator = String::compareTo;
        System.out.println(comparator.compare("abc","efj"));
    }

6.构造器引用
构造方法引用使用的要求:函数式接口的抽象方法的形参,和构造器的形参列表保持一致。抽象方法的返回值即为构造器的所属类的类型

	@Test
    public void test4(){
        Supplier supplier1 = () -> new Object();
        System.out.println(supplier1.get());

        Supplier supplier2 = Object::new;
        System.out.println(supplier2.get());
    }

7.数组引用
数组引用写法和构造器引用一样

	 @Test
    public void test5(){
        Function<Integer,String[]> function1 = length -> new String[length];
        String[] strings = function1.apply(5);
        System.out.println(Arrays.toString(strings));

        Function<Integer,String[]> function2 = String[] :: new;
        String[] strs = function2.apply(4);
        System.out.println(Arrays.toString(strs));
    }

8.Stream API(Stream(流)用于操作集合数组等
把真正的函数式编程引入到Java,Stream API 可以极大的提高生产力
1.Stream自己不会存储数据
2.Stream不会改变数据源,相反,会返回一个持有结果的新的Stream
3.操作是延迟执行的,意味着需要结果才执行

Stream的执行流程
1.Stream的实例化
2.Stream的中间操作
3.Stream的停止操作
一旦执行停止操作,就会执行中间操作链(操作数据),产生结果之后,不会再被使用

	//Stream的实例化的四种方式
	@Test
    public void test1() {
        //通过集合的方式创建Stream对象
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        //返回顺序流
        Stream<String> stream1 = list.stream();
        //返回并行流
        Stream<String> stream2 = list.parallelStream();
    }

    @Test
    public void test2() {
        //通过数组的方式创建Stream对象
        Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6};
        //返回一个顺序流
        Stream<Integer> integerStream = Arrays.stream(integers);
    }

    @Test
    public void test3() {
        //通过Stream的of()方法
        //返回一个顺序流
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
    }

    @Test
    public void test4(){
        //返回无限流
        Stream.iterate(1,t -> t * 2).limit(10).forEach(System.out::println);

        Stream.generate(Math::random).limit(5).forEach(System.out::println);
    }
	//Stream的中间操作
	@Test
    public void test1(){
        //1.筛选&&切片
        //通过集合的方式创建Stream对象
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("");
        list.add("cccc");
        list.add("ddd");
        list.add("d");
        list.add("eeeeeeee");
        /*//返回顺序流
        Stream<String> stream1 = list.stream();
        //过滤流中的元素(集合元素不为空数据),并输出
        stream1.filter(lists -> !lists.isEmpty()).forEach(System.out::println);

        //返回顺序流
        Stream<String> stream2 = list.stream();
        //截断流中部分元素
        //stream2.limit(2).forEach(s -> System.out.println(s));
        stream2.limit(2).forEach(System.out::println);

        //跳过指定个数的流中的元素,从其后操作
        list.stream().skip(4).forEach(System.out::println);

        //筛选去除重复的,通过流中元素所在类的hashCode方法,和equals方法
        list.stream().distinct().forEach(System.out::println);

        //2.映射
        list.stream().map(String::toUpperCase).forEach(System.out::println);
        list.stream().map(s -> s.toUpperCase()).forEach(s -> System.out.println(s));

        Stream<Integer> stream =  list.stream().map(String::length);
        stream.forEach(System.out::println);*/

        //3.对流中元素排序
        Stream<Integer> stream = Stream.of(1,5,4,6,9,8,3);
        stream.sorted().forEach(System.out::println);

        List<Student> listStudent = new ArrayList<>();
        listStudent.add(new Student(1,"张三"));
        listStudent.add(new Student(3,"王五"));
        listStudent.add(new Student(4,"赵六"));
        listStudent.add(new Student(2,"李四"));
        listStudent.add(new Student(2,"七七"));
        listStudent.stream().sorted((o1,o2) -> {
            if(o1 instanceof Student && o2 instanceof Student){
                Student student1 = (Student) o1;
                Student student2 = (Student) o2;
                if(o1.getId() != o2.getId()){
                    return o1.getId().compareTo(o2.getId());
                }else {
                    return o1.getName().compareTo(o2.getName());
                }
            }else {
                throw new RuntimeException("参数有误");
            }
        }).forEach(System.out::println);
    }
	//Stream的停止操作
	@Test
    public void test1() {
        //1.匹配与查找
        List<Student> listStudent = new ArrayList<>();
        listStudent.add(new Student(1, "张三"));
        listStudent.add(new Student(3, "王五"));
        listStudent.add(new Student(4, "赵六"));
        listStudent.add(new Student(2, "李四"));
        listStudent.add(new Student(2, "七七"));
        //存在一个流中元素不符合条件,则返回false
        boolean b1 = listStudent.stream().allMatch(student -> student.getId() > 3);
        System.out.println(b1);
        //存在一个流中元素符合条件,就返回true
        boolean b2 = listStudent.stream().anyMatch(student -> student.getName() != null);
        System.out.println(b2);
        //查找流中元素是否存在名字中不含有“五”
        boolean b3 = listStudent.stream().noneMatch(student -> student.getName().contains("三"));
        System.out.println(b3);
        //返回流中元素的第一个
        Optional<Student> optional1 = listStudent.stream().findFirst();
        System.out.println(optional1);

        //返回流中元素的任意一个
        Optional<Student> optional2 = listStudent.parallelStream().findAny();
        System.out.println(optional2);

        //返回流中元素的总个数
        int c = (int) listStudent.stream().filter(student -> student.getId() > 3).count();
        System.out.println(c);

        //返回最大的流中的元素
        Stream<Integer> integerStream = listStudent.stream().map(student -> student.getId());
        Optional<Integer> optionalInteger = integerStream.max(Integer::compareTo);
        System.out.println(optionalInteger);

        //返回流中指定属性所在元素的最小元素
        Optional<Student> studentOptional = listStudent.stream().min((o1, o2) -> Integer.compare(o1.getId(), o2.getId()));
        System.out.println(studentOptional);
        //这是集合的forEach
        listStudent.forEach(System.out::println);

        //2.归约
        //计算流中的元素总和
        List<Integer> list = Arrays.asList(1, 2, 5, 4, 6, 3, 9, 7, 8);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);

        Stream<Integer> iStream1 = listStudent.stream().map(student -> student.getId());
        Optional<Integer> iOptional = iStream1.reduce(Integer::sum);
        System.out.println(iOptional);

        //3.收集
        List<Student> list1 = listStudent.stream().filter(student -> student.getId() > 2).collect(Collectors.toList());
        list1.forEach(System.out::println);
        
        Set<Student> set = listStudent.stream().filter(student -> student.getId() > 2).collect(Collectors.toSet());
        set.forEach(System.out::println);
    }

9.Optional类
为了解决Java中的空指针问题而生

	@Test
    public void test1() {
        Optional optional = Optional.empty();
        if (!optional.isPresent()) {
            System.out.println("空空!!!");
        }

        //get()通常与of(T t)方法一起使用(非空)
        Integer integer = 1;
        //integer = null;
        Optional<Integer> integerOptional = Optional.of(integer);
        System.out.println(integerOptional.get());
    }

    @Test
    public void test2() {
        //通常ofNullable(T t)和orElse(T t)方法一起使用(可以为空)
        String str = "里斯";
        str = null;
        Optional<String> str1 = Optional.ofNullable(str);
        String s = str1.orElse("哈哈");
        System.out.println(s);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值