Java8新特性
java8已经出来很久了,以前看过,但平时用的还是很少,现在重新学习下,以后工作中也尽量去用新的功能,边学习边写文章记录下来加深理解
lambda表达式
还是看对列表进行排序
List<String> list = Arrays.asList("apple", "banana", "orange");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
System.out.println(list);
上面的代码在Java8里可以改写为
Collections.sort(list, (String a, String b) -> {
return b.compareTo(a);
});
System.out.println(list);
使用()->{}代替匿名函数部分,还可以更简短一些
Collections.sort(list, (String a, String b) -> b.compareTo(a));
还可以省略参数类型
Collections.sort(list, (a, b) -> b.compareTo(a));
函数式接口
Lambda表达式如何匹配Java的类型系统?每一个lambda表达式都能够通过一个特定的接口与一个给定的类型进行匹配。一个所谓的函数式接口必须要有且仅有一个抽象方法声明。每个与之对应的lambda表达式必须要与抽象的方法声明相匹配。由于默认方法不是抽象的,因此你可以在你的函数式接口里添加任意的默认方法。任意一个包含抽象方法的接口我们都可以用来做lambda表达式,为了让你的接口满足需求,你应该在接口上加上@FunctionalInterface注解。编译器会注意这个注解,如果你的接口中有第二个抽象方法,编译器会抛出异常。
@FunctionalInterface
public interface Convert<F,T>{
T convert(F from);
}
Convert<String,Integer> convert = from -> Integer.valueOf(from);
Integer integer = convert.convert("123");
System.out.println(integer);
方法和构造函数引用
上面的方法还可以使用静态方法引用
Convert<String,Integer> convert = Integer::valueOf;
Integer integer = convert.convert("123");
System.out.println(integer);
Java 8 允许你通过::关键字获取方法或者构造函数的的引用
方法引用的标准形式是 类名::方法名(只需要写方法名,不需要括号)
引用静态方法 ContainingClass::staticMethodName
引用某个对象的实例方法 containingObject::instanceMethodName
引用某个类型的任意对象的实例方法 ContainingType::methodName
引用构造方法 ClassName::new
数据流
Stream是java8引入的一个重度使用lambda表达式的API。Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。直观意味着开发者在写代码时只需关注他们想要的结果是什么而无需关注实现结果的具体方式
数据过滤
List<String> list = Arrays.asList("a1","a2","b1","c2","c1");
Stream<String> stream = list.stream();
stream = stream.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("c");
}
});
stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
引入lambda表达式改写如下
List<String> list = Arrays.asList("a1","a2","b1","c2","c1");
Stream<String> stream = list.stream();
stream = stream.filter(s -> s.startsWith("c"));
stream.forEach(System.out::println);
衔接操作
stream
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);//输出C2 C1
//mapToInt
IntStream intStream = Stream.of("1", "2", "3").mapToInt(Integer::valueOf);
intStream.forEach(value -> System.out.println(value + 1));
//mapToLong
LongStream longStream = Stream.of("1", "2", "3").mapToLong(Long::valueOf);
longStream.forEach(value -> System.out.println(value + 1));
//mapToDouble
DoubleStream doubleStream = Stream.of("1.1", "2.2", "3.3").mapToDouble(Double::parseDouble);
doubleStream.forEach(value -> System.out.println(value + 1));
//flatMap
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(1),
Arrays.asList(2, 3),
Arrays.asList(4, 5, 6)
);
Stream<Integer> outputStream = inputStream.flatMap(Collection::stream);
outputStream.forEach(System.out::println);
//reduce 这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。例如 Stream 的 sum 就相当于
String s = Stream.of("A", "B", "C", "D").reduce("A", String::concat);
System.out.println(s);//AABCD
//limit 返回 Stream 的前面 n 个元素
Stream.of("A","B","c","d").limit(2).forEach(System.out::println);
//skip 则是扔掉前 n 个元素
Stream.of("A","B","c","d").skip(2).forEach(System.out::println);
//min/max/distinct
int min = Stream.of("1","2","3","4").mapToInt(Integer::valueOf).min().getAsInt();
System.out.println(min);
int max = Stream.of("1","2","3","4").mapToInt(Integer::valueOf).max().getAsInt();
System.out.println(max);
Stream.of("1","2","2","1","3").distinct().forEach(System.out::println);
Match
Stream 有三个 match 方法,从语义上说:
- allMatch:Stream 中全部元素符合传入的 predicate,返回 true
- anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
- noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
boolean result = Stream.of(1,18,20,30,100).allMatch(integer -> integer>10);
System.out.println(result);
result = Stream.of(1,18,20,30,100).anyMatch(integer -> integer>10);
System.out.println(result);
result = Stream.of(1,18,20,30,100).noneMatch(integer -> integer>10);
System.out.println(result);
总之,Stream 的特性可以归纳为:
- 不是数据结构
- 它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
- 它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素。
- 所有 Stream 的操作必须以 lambda 表达式为参数
- 不支持索引访问
- 你可以请求第一个元素,但无法请求第二个,第三个,或最后一个。不过请参阅下一项。
- 很容易生成数组或者 List
- 惰性化
- 很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
- Intermediate 操作永远是惰性化的。
- 并行能力
- 当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并-
行进行的。 - 可以是无限的
- 集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。