Java8 学习

原创
2016/06/28 21:09
阅读数 521

每次写完代码不是一阵阵成就感,反而是挫败感加强,为什么呢?原因就是Java8特性没有使用上,导致代码的警告随处可见,作为一个程序员是不允许出现不完美的东西的,所以学习Java8迫在眉睫。啊,我一定要改变习惯,使用Java8,喊喊口号可能对自己有点安慰。

 

1、接口中可以添加非抽象方法

1)Java8 以前只允许抽象类既有抽象方法也可以由非抽象方法。

2)接口中添加非抽象方法需要使用 default 关键字限定使用。

3)功能性接口,接口只有一个抽象方法,可以有任意多个 default 声明的非抽象方法。这种接口在Lambda表达式中非常有用。Java8 提供注解 @FunctionalInterface 来限定功能性接口定义。

4)代码演示

 public interface Iter{

   default sayHello(){

        System.out.print("hello world");

   } 

 }

 

2、功能性接口

1)接口只有一个抽象方法,可以有任意多个 default 声明的非抽象方法。

2)使用 @FunctionalInterface 来限定功能性接口定义。

3)Lambda表达式结合使用

4)代码演示

@FunctionalInterface

interface Converter<F, T> {

    T convert(F from);

}

// 就是匿名实现类的对象,但是因为结合了Lambda表达式,所以简洁了很多

Converter<String, Integer> converter = (from) -> Integer.valueOf(from);

Integer converted = converter.convert("123");

 

3、:: 的使用,方法的引用

1)java8可以让你通过关键字 :: 来传递方法和构造函数的引用。

2)同样需要结合Lambda表达式,反正我是没有看到在没有Lambda表达式的情况下他是如何传递引用的。

3)静态方法和非静态方法都支持,静态方法使用类名,非静态方法使用类的对象。

4)使用 Class::new 的方式,可以创建一个简单的工厂模式,而且Lambda可以自动识别参数来找到对应的构造方法。

5)代码演示

Converter<String, Integer> converter = Integer::valueOf;

Integer converted = converter.convert("123");

 

4、Lambda 表达式

1)每个Lambda表达式都对应一个指定的类型,这个指定的类型是由接口确定。所以只能使用功能性接口时才可以使用 Lambda 表达式,否则类型无法匹配发生错误。

2)使用Lambda表达式有以下变化

     1、 匿名类可以省略。不需要显示指出实现具体接口的名称,Lambda可以自动推测接口

     2、 数据类型可以省略。不需要显示指定功能接口方法的形参类型,同样 Lambda 可以自动推测数据类型

     3、 花括号可以省略。如果只有一条语句,可以省略花括号,多条语句时必须使用花括号限定

     4、 return 可以省略。如果只有一条语句,可以省略return,多条语句时必选使用return关键字

     5、 但是多了一个 ->

3)Lambda和匿名函数一样,变量和方法的分大同小异。匿名函数调用的外部变量必须使用 final 关键字显示声明,否则编译报错;虽然,Lambda表达式可以调用非final声明的变量,但是实际上编译器作了自动转换 final,所以其实二者是一样的。

4)Lambda表达式中不能调用功能接口的 default 声明的方法,这个很特别啊,匿名函数自然是可以的。至于Lambda为什么不可以,我也不知道。

5)代码演示

        List<String> list = Arrays.asList("hello","world");

        // Java5

        Collections.sort(list, new Comparator<String>() {

            @Override

            public int compare(String o1, String o2) {

                return -(o1.compareTo(o2));

            }

        });

        // Java8

        Collections.sort(list, (a,b)->a.compareTo(b));

 

5、Java8 升级的功能性接口

1)断言接口(Predicates),Predicates是只拥有一个参数的Boolean型功能的接口。

    Predicate<Boolean> nonNull = Objects::nonNull;  // Objects 是 Java7 出来的 Object 对象帮助类

    Predicate<Boolean> isNull = Objects::isNull;

    Predicate<String> isEmpty = String::isEmpty; // 功能接口的方法是 test , 只要 isEmpty.test(obj)

    Predicate<String> isNotEmpty = isEmpty.negate(); // !isEmpty.test(obj) 等价

 

2)功能接口(Functions),Functions接受一个参数并产生一个结果。默认方法能够用于将多个函数链接在一起。功能 apply 方法接收任意参数,返回任意参数。(apply 有形参,有返回)

        Function<String, Integer> toInteger = Integer::valueOf;

        System.out.println(toInteger.apply("123")); // 123 Integer

        Function<String, String> backToString = toInteger.andThen(a->a+4+"");

        System.out.println(backToString.apply("123"));     // "127" String

 

3)供应接口(Suppliers),Suppliers对于给定的泛型类型产生一个实例。不同于Functions,Suppliers不需要任何参数,同样有任意类型的返回结果。(get 无形参,有返回)

        Supplier<Object> supplier = Object::new;

        Object obj = supplier.get();   // new Object,对象工厂

        System.out.println(Objects.toString(obj));

 

4)消费接口(Consumers),Consumers 代表在只有一个输入参数时操作被如何执行。实际上就是对一个输入参数的方法做一个统一的接口,注意他没有返回值。(accept 有形参,无返回)

        Consumer<String> consumer = (str) -> System.out.println("Hello, " + str);

        consumer.accept("World!");

 

5)比较接口(Comparators),Java8 在以前的基础上添加了许多方法,这里 Comparator 除了有 default 声明的方法之外,还有许多 static 的方法。

以前学习Java的时候明确指定静态方法不能被重写,所以接口中不应该出现static方法,因为接口中的方法就是需要子类去实现的,不能被重写和实现导致冲突,然而现在,接口中有了default,也有了static的方法,感觉接口已经不是以前那么单纯的接口了,反而是一些方法的集合体。

Comparator<String> comparator = (p1, p2) -> p1.compareTo(p2);

comparator.reversed().compare(p1, p2);  // < 0

 

6)选项接口(Optionals),Optionals并不是功能性接口,它是一种工具,比如有 map 、filter 等方法。 类的声明 public final class Optional<T>

        Optional<String> optional = Optional.of("bam");

        optional.isPresent();           // true

        optional.get();                 // "bam"

        optional = optional.map(a-> a+" died"); // bam died 

 

7)流接口(Streams),主要改变是 链式调用,串行操作,并行操作 

java.util.Stream代表着一串你可以在其上进行多种操作的元素。流操作既可以是连续的也可以是中断的。中断操作返回操作结果。而连续操作返回流本身,这样你就可以在该行上上继续操作。流是创建在数据源上的,例如:java.util.Collection、list集合和set集合。流操作既可以顺序执行也可以并行执行。

        List<String> list = Arrays.asList("1","5","3");

        list.stream().forEach(System.out::print); // 串行遍历集合

        list.parallelStream().forEach(System.out::print); // 并行遍历集合

        list.sort((a,b)-> - a.compareTo(b)); // 排序

        list.forEach(System.out::print); // 遍历

 

8)流接口下运用的方法(Filter)、(Sorted),(Map),(Match)、(Count)、(Reduce)

1)Filter接受一个predicate来过滤流中的所有元素。这个操作是连续的。ForEach接受一个consumer,它被用来对过滤流中的每个元素执行操作。ForEach是一个中断操作,因此我们不能在ForEach后调用其他流操作。

2)Sorted是一个连续操作,它返回流的已排序版本。如果你没有显示的指定Comparator,那么流中元素的排序规则为默认的。

3)连续性操作map通过指定的Function将流中的每个元素转变为另外的对象。

4)各种匹配操作可以用来检测是否某种predicate和流中元素相匹配。所有的这些操作是中断的并返回一个boolean结果。

5)Count是中断型操作,它返回流中的元素数量。这个和 size 很相似,当然是有差异的,size是对象本身的长度,count是对象副本的长度。

6)Reduce中断性操作使用指定的function对流中元素实施消减策略。此操作的返回值是一个包括所有被消减元素的Optional。

        list.stream().filter(value->Objects.equals(value,"5")).forEach(System.out::print); // 这里需要注意,list本身并没有发生改变,改变只是连续操作的对象副本。

        list.stream().sorted((a,b)->a.compareTo(b)).forEach(System.out::print); // 同上,排序不会改变List对象本身,改变的是操作流对象副本。

        list.stream().map(value->value+"_suffix").forEach(System.out::print); // 同上,List对象本身不会被改变

        System.out.println(list.stream().anyMatch(value->value.equals("5")));

        System.out.println(list.stream().allMatch(value->value.equals("5")));

        System.out.println(list.stream().noneMatch(value->value.equals("5")));

        System.out.println(list.stream().count() == list.size());

        Optional o = list.stream().reduce((s, s2) -> s+"_"+s2); o.ifPresent(System.out::print); // 1_5_3 

 

9)Map 新增操作

1)使用 foreach 遍历集合 

2)使用compute操作一对指定key的映射

        map.putIfAbsent(null,"empty"); // 使用 put 可以存储 null,null,但是如果使用 putIfAbsent ,只能存储同时不为null的映射

        map.forEach((s, o) -> System.out.println(s+":"+o)); // 遍历集合

        map.computeIfPresent("kitty", (key, val) -> val +"_"+ key); // 操作指定key的映射

        map.get("kitty");      

        map.computeIfAbsent("kitty", key -> "val" + key);  // 操作指定key的映射

        map.get("kitty");

 

展开阅读全文
打赏
1
24 收藏
分享
加载中
更多评论
打赏
0 评论
24 收藏
1
分享
返回顶部
顶部