Java8在平时工作中被普及的越来越多了,而且Java8也是Java的一次重大版本升级。平时工作中的项目都已经使用了jdk1.8版本,但是关于新特性基本没怎么用到,鉴于平时工作时开始慢慢推行Java8新特性编程,面试中有时候也会涉及到这方面的问题。在此做一个总结,希望自己能有所提高也能帮助别人。
一、Lambda表达式
先看一个lambda表达式的简单例子
//老版本
List<String> fruits = Arrays.asList("apple", "banana", "orange", "watermelon");
for (String fruit : fruits) {
System.out.print(fruit + "!");
}
//Java8新特性
System.out.println();
fruits.forEach(e -> System.out.print(e + "!"));
可以看出lambda表达式的语法类似:
元素 -> 表达式
二、函数式接口(Functional Interface)
Java使用了很多函数式接口来隐式转换lambda表达式,可以看一下上面的源码:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
进入Consumer里面查看源码,其实Cosumer代表了接受一个输入参数并且无返回的操作
@FunctionalInterface
public interface Consumer<T> {
/**
* 对参数做指定操作
* @param t the input argument
*/
void accept(T t);
}
接口的@FunctionalInterface注解,表明该接口为为函数式接口。
函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
大部分函数式接口我们平时使用时并不用管,Java已经基本实现了大部分。
以下是一个函数式接口的例子(Java8之前一般使用匿名类来实现):
@FunctionalInterface
public interface FruitService {
void printFruitName(String fruitName);
}
public class FruitTest {
public static void main(String[] args) {
FruitService fruitService = fruit -> System.out.println(fruit + "!");
fruitService.printFruitName("apple");
}
}
Java8新增加的包涵了大部分函数式接口的接口为java.util.function
三、方法引用
方法引用通过方法的名字来指向一个方法。方法引用可以使语言的结构更紧凑简洁,减少冗余代码。方法引用使用一对冒号 :: 来表示。
下面的实例定义了几种方法做实例:
public class Computer {
public Computer() {
System.out.println("Create a computer!");
}
public static String askComputer(){
System.out.println("Where is my computer?");
return "Where?";
}
public void powerOn(Computer computer) {
System.out.println(computer.toString() + "+++++++开机");
}
public static void downKeyBoard(Computer computer){
System.out.println(computer.toString() + "++++++++敲敲键盘");
}
public void powerOff(){
System.out.println("+++++++关机");
}
}
- **构造器引用:**它的语法是Class::new,或者更一般的Class< T >::new
Supplier<Computer> computerSupplier = Computer::new;
Computer computer = computerSupplier.get();
- 静态方法引用: 它的语法是Class::static_method
Supplier<String> askComputer = Computer::askComputer;
System.out.println(askComputer.get());
- 特定类的任意对象的方法引用: 它的语法是Class::method
computers.forEach(Computer::powerOff);
- 特定对象的方法引用: 它的语法是instance::method
List<Computer> computers = Arrays.asList(computer);
computers.forEach(computer::powerOn);
测试类如下:
public static void main(String[] args) {
Supplier<String> askComputer = Computer::askComputer;
System.out.println(askComputer.get());
Supplier<Computer> computerSupplier = Computer::new;
Computer computer = computerSupplier.get();
System.out.println("计算机名:" + computer.toString());
List<Computer> computers = Arrays.asList(computer);
computers.forEach(computer::powerOn);
computers.forEach(Computer::downKeyBoard);
computers.forEach(Computer::powerOff);
}
执行结果:
四、默认方法
Java8新增了接口的默认方法,即接口可以有实现的方法,而且不需要类去实现其方法。
看一下下面的例子就明白了。
public interface Computer {
default void selfIntroduce(){
System.out.println("我是一台计算机");
}
}
public interface KeyBoard {
default void selfIntroduce(){
System.out.println("我是一个键盘");
}
}
public class Laptop implements Computer,KeyBoard{
@Override
public void selfIntroduce() {
Computer.super.selfIntroduce();
KeyBoard.super.selfIntroduce();
System.out.println("我是一台笔记本电脑");
}
}
public class Test {
public static void main(String[] args) {
Computer laptop = new Laptop();
laptop.selfIntroduce();
}
}
运行结果如下:
五、Stream
Java8一个重要的特性就是流Stream,可以让我们以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
5.1 什么是流
流(Stream)是一个来自数据源的元素队列并支持聚合操作。
先看一个实例:
public static void main(String[] args) {
List<String> strings = Arrays.asList("1", "2", "3", "4", "5", "6");
List<String> list = strings.stream().map(i -> i + "0").collect(Collectors.toList());
System.out.println(list.toString());
}
结果如下:
可以看到stream流的使用还是很简洁的。
主要的语法格式为:获取数据源转换为元素流,元素流在管道中经过中间操作处理,最终由最终操作得到前面处理的结果
5.2 生成流的方法
- stream() – 为集合创建串行流
- parallelStream() – 为集合创建并行流
刚刚的例子用的就是stream方法生成了流,从而对数据源进行操作
5.3 流的中间操作
map: 用于映射每个元素到对应的结果,如开始的例子
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> integerList = nums.stream().map(x -> x*x).collect(Collectors.toList());
System.out.println(integerList);
filter: 通过设置条件,将符合条件的元素过滤出来
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> collect = nums.stream().filter(num -> (num % 2 == 0)).collect(Collectors.toList());
System.out.println(collect.toString()); //[2, 4, 6]
limit: 用于获取指定数量的流
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> collect1 = nums.stream().limit(3).collect(Collectors.toList());
System.out.println(collect1.toString()); //[1, 2, 3]
distinct: 提出重复元素
List<Integer> nums = Arrays.asList(1, 2, 3, 2, 3, 1);
List<Integer> integerList = nums.stream().map(x -> x*x).distinct().collect(Collectors.toList());
System.out.println(integerList);//[1, 4, 9]
sorted: 对流进行排序
List<Integer> nums = Arrays.asList(1, 2, 3, 2, 3, 1);
List<Integer> integerList = nums.stream().sorted().collect(Collectors.toList());
System.out.println(integerList);//[1, 1, 2, 2, 3, 3]
5.4 流的终结操作
5.4.1 收集操作
collection(Collection c): Collectors类实现了很多归约操作,如上面的例子经常用过ollect(Collectors.toList())
5.4.2 查找操作
- allMatch(Predicate p) 返回匹配的元素
- findFirst() 返回第一个元素
- count() 反馈元素总数
- forEach(Consumer c) 这个比较常用
操作有很多,具体还是用的时候百度下参考
六、结论
Java8增加了很多新特性,虽然大部分编程时还是使用以前的编程习惯。但是有的公司可能已经在开始推荐Java8新特性习惯的开发,尤其是使用stream流方面。
因此,学习新的特性,为以后做好准备还是可以的。
参考资料:菜鸟教程 https://www.runoob.com/java/java8-new-features.html