1.接口默认方法(Default Methods for Interfaces)
  • Java 8能够通过使用default关键字向接口添加非抽象方法实现,此功能成为虚拟扩展方法
    1
    2
    3
    4
    5
    6
    interface Formula{
    double calculate(int a);
    default double sqrt(int a){
    return Math.sqrt(a);
    }
    }
  • Formula接口中除了抽象方法计算接口公式还定义了默认方法sqrt。实现该接口的类只需要实现抽象方法calculate。默认方法sqrt可以直接使用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Main{
    public static void main(String[] args){
    Formula formula = new Formula(){
    @Override
    public double calculate(int a){
    return sqrt(a * 100);
    }
    };
    System.out.println(formula.calculate(100));
    System.out.println(formula.sqrt(100));
    }
    }
2.lambda表达式(lambda expressions)
1
2
3
4
5
6
7
List<String> names = Arrays.asList("peter", "anna", "mike", "xenis");
Collections.sort(names, new Comparator<String>(){
@Override
public int compare(String a, String b){
return b.compareTo(a);
}
});

Lambda表达式写法

1
2
3
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});

1
Collections.sort(names, (String a, String b) -> b.compareTo(a));
1
names.sort((a, b) -> b.compareTo(a));
3. 函数式接口
  • 函数式接口值仅仅只包含一个抽象方法,但可以有多个非抽象方法(默认方法)的接口。
  • 可以隐式转换成lambda表达式,java.lang.Runnable, java.util.concurrent.Callable。
  • @FunctionalIterface
  • 只要接口包含一个抽象方法,虚拟机会自动判断该接口为函数式接口。
    1
    2
    3
    4
    @FunctionalInterface
    public interface Converter<F, T>{
    T convert(F form);
    }
1
2
3
// 将数字类型转成整数类型
Converter<String, Integer> converter = (form) -> Integer.valueOf(form);
Integer converted = converter.convert("123");
  • Java8允许通过:: 关键字传递方法或构造函数的引用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 对象引用
    class Something {
    String startWith(String s){
    return String.valueOf(s.charAt(0));
    }
    }

    Something something = new Something();
    Converter<String, String> converter = something::startWith;
    String converted = converter.convert("Java"); // "J"
  • 构造函数使用::关键字来引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Person {
    String firstName;
    String lastName;

    Person(){}

    Person(String firstName, String lastName){
    this.firstName = firstName;
    this.lastName = lastName;
    }
    }

    // 指定一个用来创建Person对象的对象工厂接口
    interface PersonFactory<P extends Persion>{
    P create(String firstName, String lastName);
    }

    // 使用构造函数引用来讲他们关联起来
    PersonFactory<Person> personFactory = Person::new; // 这里使用Person:new来获取Person类构造函数的引用
    Person person = personFactory.create("Peter", "Parker");
  • Lambda表达式作用域

    • 访问局部变量

      1
      2
      3
      4
      5
      // final int num = 1;
      int num = 1; // 可以不用final修饰,但是后面不能修改num
      Converter<Integer, String> stringConverter = (form) -> String.valueOf(form + num);

      stringConverter.convert(2); // 3
    • 访问字段和静态变量: 对lambda表达式中的实例字段和静态变量都有读写访问权限,和匿名对象一致。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      class Lambda4 {
      static int outerStaticNum;
      int outerNum;

      void testScopes() {
      Converter<Integer, String> stringConverter1 = (from) -> {
      outerNum = 23;
      return String.valueOf(from);
      };

      Converter<Integer, String> stringConverter2 = (from) -> {
      outerStaticNum = 72;
      return String.valueOf(from);
      };
      }
      }
    • 方位默认接口方法: 无法从lambda表达中访问默认方法。

      5.内置函数式接口

      JDK1.8中包含了许多内置函数式接口

  • Predicates:只有一个参数的返回Boolean类型值的断言型接口。该接口包含许多默认方法将Predicate组合成其他复杂逻辑(与或非)
  • Optionals:用户防止NullPointerException的工具
6.Streams流
  • java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
  • Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection 的子类,List 或者 Set, Map 不支持。Stream 的操作可以串行执行或者并行执行
  • 过滤Filter

    • 过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作
      1
      2
      3
      4
      stringList.stream()
      .filter((s) -> s.startWith('a'))
      .forEach(System.out::println);
      // forEach 是为 Lambda 而设计的,保持了最紧凑的风格
  • Sorted(排序)

    • 排序是一个中间操作,返回排序后的Stream
    • 排序只创建一个排列好的Stream,而不影响原有的数据源,排序之后原数据stringCollection不会被修改。
      1
      2
      3
      4
      5
      6
      7
      stringList.stream()
      .sorted()
      .filter((s) -> s.startsWith("a"))
      .forEach(System.out::println);
      ```
      + Map(映射)
      - 中间操作map会将元素根据指定的Function接口来一次将元素转成另外的对象。

stringList.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);

1
2
+ Match(匹配)
- Stream提供的匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,返回Boolean。

boolean anyStartsWithA = stringList.stream()
.anyMath((s)->s.startsWith(“a”)); // True

1
2
+ Count(计数)
- 计数是一个最终操作,返回stream中元素的个数,返回类型是long。

long startsWithB = stringList.stream()
.filter((s) -> s.startsWith(“b”))
.count();

1
2
+ Reduce(规约)
- 最终操作,允许通过指定的函数来将stream中的对各元素规约为一个元素。

Optional reduced = stringList.stream()
.sorted()
.reduce((s1, s2) -> s1 + “#” + s2);
reduced.ifPresent(System.out::println);//aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2
`

  • Parallel Streams(并行流)
  • Sequential Sort(串行排序)
  • Parallel Sort(并行排序)
  • Maps
  • Date API
  • Annotations(注解)