@[JAVA8的语法新特性]
昨天公司开了一节培训课给新员工讲解Java8的语法新特性,便于刚入职的新员工能写出简洁的代码。多了解编程语言新版本的特性好处不少,一是新特性使得我们在开发过程中能化繁为简,同时又能让读者容易理解。二是在后续的秋招中当面试官问我们有没有了解过JAVA8,C++14的新特性时不至于说不出话来。如果能够讲出自己对lambda,stream等的理解和使用经历,相信也是一个加分项。
1.try-with-resource
以往,我们使用完资源对象后总需要在finally语法块中关闭资源对象,标准的写法可以说是十分冗余。
InputStreamReader in=null;
try {
in = new InputStreamReader(System.in);
int temp;
while ((temp = in.read()) != '\n') {
System.out.println((char)temp);
}
} catch (IOException e) {
System.err.println(e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
System.err.println(e);
}
}
使用try-with-resource可以声明一种或多种资源的try语句,并且其保证了每个声明了的资源在语句结束的时候都会被关闭。
try (InputStreamReader inputStreamReader = new InputStreamReader(System.in)) {
int temp;
while ((temp = inputStreamReader.read()) != '\n') {
System.out.println((char)temp);
}
} catch (IOException e) {
System.err.println(e);
}
2.接口的default方法
Java8中的接口允许函数有默认实现,同时接口中允许出现静态方法,但是只能通过接口名调用。default 方法的出现,使得我们给接口添加新功能变得方便。我们在给接口添加新功能时不再需要考虑老代码中实现了这个接口的类如何更新,因为接口中有默认实现。而在需要的类中可以重写该方法,这在项目开发中,尤其是需要考虑兼容不同版本的应用来说是较为方便的。(这里有一个小疑问,为什么不直接再实现一个接口呢,这样的扩展性不是更好吗?)
public interface A {
public default void a(){
System.out.println("这是A");
}
}
这里需要注意的有两点:
如果一个类实现的两个接口中有相同的default函数,则子类需要自己实现该函数
如果一个类实现的接口中的default方法和继承的父类中的某个方法相同,则子类默认继承父类中的该方法
3.lambda表达式
lambda表达式配合函数式接口(只有一个未实现方法的接口,常见的有Runnable,Callable,Comparable)使用,让我们避免再去写冗余的匿名内部类代码,让代码可以像德芙巧克力一样顺滑。
lambda表达式代替匿名内部类
new Thread(() -> System.out.println("This is a new thread")).start();
如果你想执行多个语句,可以在箭头后加上大括号放入。
lambda表达式对列表进行迭代
List list = Arrays.asList("广州","深圳","珠海","汕头");
list.forEach(n -> System.out.println(n));
lambda表达式与predicate接口配合使用
public void filter (List<String> list, Predicate<String> condition) {
list.forEach(name -> {
if (condition.test(name)) {
System.out.print(name + " ");
}
});
System.out.println();
}
public void predicateTest() {
List<String> provinces = Arrays.asList("广东","广西","山西","山东");
System.out.println("province start with 广");
filter(provinces, (str) -> str.startsWith("广"));
System.out.println("province end with 西");
filter(provinces, (str) -> str.endsWith("西"));
System.out.println("all provinces in list");
filter(provinces, (str) -> true);
}
当然,你也可以自己实现一个函数式接口。使用注解@FunctionInterface表示这个接口只能拥有一个未实现的方法。
java中常见的函数式接口
Consumer, Function, Supplier, UnaryOperator, BinaryOperator
lambda表达式的限制
lambda表达式中只能引用final或者final局部变量,也就是说不能在lambda内部修改定义在域外的变量。
4.Stream
构建流对象的方式
-
Stream.of()
Stream<String> stream = Stream.of("a","b","c");
-
Collection.stream()
List<String> strings = Arrays.asList("a","b","c"); Stream<String> stream = strings.stream();
-
Stream.generate()
Stream<Double> stream = Stream.generate(() -> { retrun Math.random(); }).limit(5);
-
使用iterate()
Stream<Integer> stream = Stream.iterate(1, i->i+1).limit(5);
转换流为集合
Stream<Integer> stream = Stream.iterate(10, i -> i + 1).limit(10);
转换为List
List<Integer> list = stream.filter(i -> i % 2 != 0).collect(Collectors.toList());
转换为Set
Set<Integer> set = stream.filter(i -> i % 2 != 0).collect(Collectors.toSet());
转换为数组
Integer[] array = stream.filter(i -> i % 2 != 0).toArray(Integer[]::new);
常用流操作
使用filter()过滤流中的元素
使用如上
多条件组合过滤
Predicate<String> pre1 = n -> n % 2 = 0;
Predicate<String> pre2 = n -> n % 3 = 0;
stream.filter(pre1.and(pre2));
使用map()把流中的元素转换为另一个对象
stream.map(i -> i*10);
使用sorted()对流中的元素进行排序
默认按照自然序排序,也可以自定义Comparator。
我们可以定义反向排序如下
stream.sorted((a, b) -> {
if (a < b)
return 1;
else if (a > b)
return -1;
else
return 0;
}).forEach(i -> System.out.println(i));
foreach()
使用如上
collect()
用来抽取元素保存到集合或者数组中,使用如上
count()
流中元素计数
(any/all/none)match()
用来判断流中的元素是否都满足,任意满足,都不满足断言条件。注意匹配操作时末端操作,直接返回布尔结果。
reduce()
暂不熟悉,后续补充。。。
并行流
暂不熟悉,后续补充。。。