文章内容
1.匿名类
2.函数式接口
3.lambda表达式
4.lambda表达式、函数接口和Stream接口在数据处理上的运用
1.匿名类
匿名类,即没有名字的类,只能使用一次,匿名类的实现主要通过两种方式:继承和接口,需要注意的是匿名类由于没有类类型,对外可见的属性和方法必须是在父类或接口中定义;
①继承方式实现
继承父类病重写父类方法,本应该是新的类,如果只是临时使用不需要创建新的类类型,直接在实例化时重写父类方法;
public class Parent {
public void print(){
System.out.println("parent");
}
}
Parent p1 = new Parent(){
@Override
public void print(){
System.out.println("extends:AnysMain");
}
};
②接口方式实现
接口的实现根据具体的调用上下实现决定,没有固定的实现;在使用时,定义接口类型并实现接口方法;也就成了匿名的实现类;
public interface IParent {
public void print();
}
IParent p2 = new IParent(){
@Override
public void print() {
System.out.println("interface:AnysMain");
}
};
p2.print();
2.函数式接口
只有一个特有抽象方法的接口(不包括继承来的接口),@FunctionalInterface,简称FI;
@FunctionalInterface
public interface IFuncInterface {
public void print();
}
在Java8中与lambda表达式相关的函数式接口:
①Predicate接口(逻辑判断)
虽然Predicate接口有5个方法,但是除了test方法,其他方法都属于默认方法(default修饰的抽象方法,有默认实现),则在创建接口相关的实例时只需要实现test方法;
//Returns a predicate which evaluates to true only if this predicate
//and the provided predicate both evaluate to true.
and(Predicate<? super T> p)
//Returns a predicate which negates the result of this predicate.
negate()
//Returns a predicate which evaluates to true if either
//this predicate or the provided predicate evaluates to true
or(Predicate<? super T> p)
//Returns true if the input object matches some criteria
test(T t)
//Returns a predicate that evaluates to true if both or neither
//of the component predicates evaluate to true
xor(Predicate<? super T> p)
②Consumer接口(附加操作)
Consumer接口有两个方法,同样的只有一个抽象方法accept,用于接收参数并对参数进行操作;
/**
* Performs this operation on the given argument.
*/
void accept(T t);
/**
* 完成链式操作
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
③Function接口(对象操作)
对对象T进行处理并返回独享R,唯一的抽象方法为apply,除此之外还有附属的操作,比如andThen、compose、identity;
– | – |
---|---|
default Function andThen(Function after) | Returns a composed function that first applies this function to its input, and then applies the after function to the result. |
R apply(T t) | Applies this function to the given argument. |
default Function compose(Function before) | Returns a composed function that first applies the before function to its input, and then applies this function to the result. |
static Function identity() | Returns a function that always returns its input argument. |
④Supplier 接口(提供对象)
用于返回一个泛型T对象;
T get() | Gets a result. |
⑤Comparator 接口(比较规则)
Comparator接口是一个经典的接口,一般自定义的比较规则都是通过Comparator接口来实现的;除了一个compare(T o1, T o2)方法,Java8中实现了大量的默认方法;
int compare(T o1, T o2) | Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. |
default Comparator reversed() | Returns a comparator that imposes the reverse ordering of this comparator. |
default Comparator thenComparing(Comparator other) | Returns a lexicographic-order(字典序) comparator with another comparator. |
default Comparator thenComparing(Function keyExtractor,Comparator keyComparator) | Returns a lexicographic-order comparator with a function that extracts a key to be compared with the given Comparator. |
default Comparator thenComparing(Function keyExtractor, Comparator keyComparator) | Returns a lexicographic-order comparator with a function that extracts a key to be compared with the given Comparator. |
default Comparator thenComparingDouble(ToDoubleFunction keyExtractor) | Returns a lexicographic-order comparator with a function that extracts a double sort key. |
default Comparator thenComparingInt(ToIntFunction keyExtractor) | Returns a lexicographic-order comparator with a function that extracts a int sort key. |
default Comparator thenComparingLong(ToLongFunction keyExtractor) | Returns a lexicographic-order comparator with a function that extracts a long sort key. |
除了以上常用函数接口,还有一些其他有用的Java8提供的新特性;
⑥Optional 接口
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
在大量数据处理的过程中,会不可避免的出现null的问题,使用Optional接口可以很好的简化对null的判断;
一般通过Optional提供的静态方法of/ofNullable封装实例对象;
//java.util.Optional<T> 类的声明
public final class Optional<T> extends Object
方法 | 描述 |
---|---|
static Optional empty() | 返回空的 Optional 实例。 |
boolean equals(Object obj) | 判断其他对象是否等于 Optional。 |
Optional filter(Predicate predicate) | 如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。 |
Optional flatMap(Function> mapper) | 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional |
T get() | 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException |
int hashCode() | 返回存在值的哈希码,如果值不存在 返回 0。 |
void ifPresent(Consumer consumer) | 如果值存在则使用该值调用 consumer , 否则不做任何事情。 |
boolean isPresent() | 如果值存在则方法会返回true,否则返回 false。 |
Optional map(Function mapper) | 如果存在该值,提供的映射方法,如果返回非null,返回一个Optional描述结果。 |
static Optional of(T value) | 返回一个指定非null值的Optional。 |
static Optional ofNullable(T value) | 如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。 |
T orElse(T other) | 如果存在该值,返回值, 否则返回 other。 |
T orElseGet(Supplier other) | 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。 |
T orElseThrow(Supplier exceptionSupplier) | 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常 |
⑦Stream 接口
java.util.Stream 表示能应用在一组元素上一次执行的操作序列,用于对集合类型完成一系列操作,包括过滤、遍历;重点是可以由集合生成stream和parallelStream两种类型的流,parallelStream支持并行计算分而治之,将多个中间操作划分到不同的线程来完成
Filter过滤:过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作;
Sort排序:排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序(需要集合类型实现Comparable接口);
Map映射:中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象;
Match匹配:Stream提供了多种匹配操作(allMatch/anyMatch),所有的匹配操作都是最终操作,并返回一个boolean类型的值。
Count计数:计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。
Reduce规约:这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的;
//stream相关操作
List<Example> list = new ArrayList<Example>();
list.add(new Example(3, "alice"));
list.add(new Example(4, "eric"));
list.add(new Example(5, "luice"));
list.add(new Example(1, "tom"));
list.add(new Example(2, "bob"));
//count
System.out.println(list.stream().count());
//match
System.out.println(list.stream().allMatch((e)->e.index > 0));
//reduce
System.out.println(list.stream().reduce((before,next)->{
before.name = before.name+"/"+next.name;
return before;
}).get().name);
System.out.println(list.stream().reduce(new Example(-1,""),(before,next)->{
before.name = before.name+"/"+next.name;
return before;
}).name);
//sorted
list
.stream()
.sorted((e1,e2)->{return e1.index - e2.index;})
.forEach((e) -> {System.out.println(e.name);});
3.lambda表达式
lambda表达式是匿名方法,它提供了轻量级的语法,从而解决了匿名内部类带来的“高度问题”,是Java8提供的一种很轻量的语法规则;
(int x, int y) -> x + y
() -> 42
(String s) -> { System.out.println(s); }
第一个lambda表达式接收x和y这两个整形参数并返回它们的和;第二个lambda表达式不接收参数,返回整数’42’;第三个lambda表达式接收一个字符串并把它打印到控制台,不返回值。
lambda表达式的语法由参数列表、箭头符号->和函数体组成。函数体既可以是一个表达式,也可以是一个语句块:
表达式:表达式会被执行然后返回执行结果。
语句块:语句块中的语句会被依次执行,就像方法中的语句一样——
return语句会把控制权交给匿名方法的调用者
break和continue只能在循环中使用
如果函数体有返回值,那么函数体内部的每一条路径都必须返回值
表达式函数体适合小型lambda表达式,它消除了return关键字,使得语法更加简洁。
4.lambda表达式、函数接口和Stream接口在数据处理上的运用
借助lambda表达式在语法上简洁、以及函数接口的设计,可以完成复杂的数据处理逻辑;特别的,对于集合类数据(目前大部分数据来源为集合),Java8提供了Stream接口,并且定义了Sorted、Match、Filter等中间操作实现对数据的过滤;以及Count、Map、Reduce等最终操作完成对数据的聚合处理;