Java8新特性
Java8的新特性主要是lambda表达式和流,它是推动 Java 8 发布的最重要新特性,允许把函数作为一个方法的参数(函数作为参数传递进方法中)使用 Lambda 表达式可以使代码变的更加简洁紧凑
为什么要学函数式编程
面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。现实世界中,数据和行为并存,程序也是如此,因此这两种编程方式我们都得学
和匿名内部类的比较
设计匿名内部类的目的,就是为了方便 Java 程序员将代码作为数据传递。不过,匿名内部类还是不够简便
入门示例:
代码语言:javascript复制button.addActionListener(event -> System.out.println("button clicked"));
说明:event 是参数名,-> 将参数和 Lambda 表达式的主体分开,在Lambda 表达式中无需指定参数类型
如何辨别Lambda表达式
简单示例: 1 Lambda 表达式不包含参数,使用空括号 () 表示没有参数。该 Lambda 表达式实现了 Runnable 接口,该接口也只有一个 run 方法,没有参数,且返回类型为 void
代码语言:javascript复制Runnable noArguments = () -> System.out.println("Hello World");
2 Lambda 表达式包含且只包含一个参数,可省略参数的括号
代码语言:javascript复制ActionListener oneArgument = event -> System.out.println("button clicked");
3 Lambda 表达式的主体不仅可以是一个表达式,而且也可以是一段代码块,使用大括号({})将代码块括起来,如下所示。该代码块和普通方法遵循的规则别无二致,可以用返回或抛出异常来退出。只有一行代码的 Lambda 表达式也可使用大括号,用以明确 Lambda表达式从何处开始、到哪里结束
代码语言:javascript复制Runnable multiStatement = () -> {
System.out.print("Hello");
System.out.println(" World");
};
4 Lambda 表达式也可以表示包含多个参数的方法,如下所示。这时就有必要思考怎样去阅读该 Lambda 表达式。这行代码并不是将两个数字相加,而是创建了一个函数,用来计算两个数字相加的结果。变量 add 的类型是BinaryOperator,它不是两个数字的和,而是将两个数字相加的那行代码。
代码语言:javascript复制BinaryOperator<Long> add = (x, y) -> x y;
也可指定参数类型: BinaryOperator addExplicit = (Long x, Long y) -> x y;
将 Lambda 表达式赋值给一个局部变量,或传递给一个方法作为参数,局部变量或方法参数的类型就是 Lambda 表达式的目标类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的函数接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型
java中重要的函数接口:
第二部分:流(Stream API)
什么是流:流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算 作用:流使程序员得以站在更高的抽象层次上对集合进行操作,和 Iterator 类似,Stream 是一种内部迭代方式。将 Lambda 表达式和Stream 上的方法结合起来,可以完成很多常见的集合操作。
Java 程序员在使用集合类时,一个通用的模式是在集合上进行迭代,然后处理返回的每一个元素 List接口中的stream()函数
代码语言:javascript复制default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Stream接口当中包含的方法:
- Stream接口中的方法的参数就是一个函数式接口
测试案例1:
代码语言:javascript复制 @Test
public void stream01(){
List<Integer> list = new ArrayList<>();
list.add(1232);
list.add(435345);
list.add(657868);
list.stream().forEach(i -> System.out.println(i));
System.out.println(list.stream().count()); // count函数用
于输出集合中元素个数
}
打印结果:
1232
435345
657868
stream.filter一般适用于list集合,从集合中查询想要的数据
代码语言:javascript复制 list.stream().forEach(System.out::println);
代码语言:javascript复制@Test
public void stream02(){
List<Integer> list = new ArrayList<>();
list.add(1232);
list.add(435345);
list.add(657868);
list.add(null);
list.stream().filter(StringUtils::isNotBlank).forEach(System.out::println); //将等于null的过滤出来再打印
list.stream().filter(i -> i>12344).forEach(j -> System.out.println(j));
}
这个意思是指:筛选出list集合中值大于12344的结果,然后将其打印出来
输出结果:
435345
657868
另外一种写法:
代码语言:javascript复制 @Test
public void stream02(){
List<Integer> list = new ArrayList<>();
list.add(1232);
list.add(435345);
list.add(657868);
List<Integer> li = list.stream().filter(i -> i>12344).collect(Collectors.toList());
li.forEach(j -> System.out.println(j));
}
返回结果:
435345
657868
map流映射
map 操作就可以使用该函数,将一个流中的值转换成一个新的流。
代码语言:javascript复制@Test
public void map(){
List<String> list = new ArrayList<>();
list.add("sssasdf");
list.add("ahj");
list.add("kdf");
list.stream().map(r -> r.toUpperCase()).forEach(j -> System.out.println(j));
}
得到的结果:
SSSASDF
AHJ
KDF
对map的遍历:
代码语言:javascript复制 @Test
public void map1(){
Map<String, String> map = new HashMap<>();
map.put("name", "啊啊");
map.put("age", "11");
map.forEach((k,v) -> {
if ("name".equals(k)) {
System.out.println(k);
}
});
}
输出结果:name
如果仅需打印的话:
map.forEach((k,v) -> System.out.println(k)); //打印K值
map.forEach((k,v) -> System.out.println(v)); //打印V值
方法引用
Java 8 为其提供了一个简写语法,叫作方法引用,帮助程序员重 用已有方法。用方法引用重写上面的 Lambda 表达式,代码如下: Artist::getName 标准语法为 Classname::methodName。需要注意的是,虽然这是一个方法,但不需要在后面加括号,因为这里并不调用该方法。我们只是提供了和 Lambda 表达式等价的一种结构,在需要时才会调用。凡是使用 Lambda 表达式的地方,就可以使用方法引用。
如果你想使用 Lambda 表达式创建一个 Artist 对象,可能会写出如下代码: (name, nationality) -> new Artist(name, nationality) 使用方法引用,上述代码可写为: Artist::new 这段代码不仅比原来的代码短,而且更易阅读。Artist::new 立刻告诉程序员这是在创建一个 Artist 对象,程序员无需看完整行代码就能弄明白代码的意图。另一个要注意的地方是方法引用自动支持多个参数,前提是选对了正确的函数接口。
相关参考文章链接:https://mp.weixin.qq.com/s/7l6FVTti9yKHHVUWIyemtA