1. Lambda 表达式
1.1 概述
- Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
@Test
public void myTest() {
Integer[] ints = {8, 4, 7, 2, 9, 5};
List<Integer> list = Arrays.asList(ints);
//之前的排序
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
System.out.println(list); // [9, 8, 7, 5, 4, 2]
//使用Lambda表达式
list.sort((o1,o2)->(o1-o2));
System.out.println(list); // [2, 4, 5, 7, 8, 9]
}
1.2 语法
(params) -> expression
或
(params) -> { statements; }
1.3 特征
- 一个参数可以不用定义圆括号,无参或多个参数必须定义圆括号。
- 如果主体只有一个语句,可以不需要使用大括号,编译器会自动返回值;如果主体有多个语句,就必须使用大括号,并且需要指定一个返回值。
1.4 示例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 不需要参数,返回值为 5
() -> { return 5; }
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
1.5 变量作用域
- 在 lambda 表达式中可以捕获外围作用域中变量的值。
- 在 lambda 表达式的体与嵌套块有相同的作用域,所以在 lambda 表达式中声明与一个局部变量同名的参数或局部变量是不合法的。
- 在 lambda 表达式中,只能引用 值不会改变的变量。
- 在 lambda 表达式中捕获的变量必须实际上是最终变量 (effectively final)。
- 在一个 lambda 表达式中使用 this 关键字时,是指创建这个 lambda 表达式的方法的 this 参数。
public void countDown(long num){
// num++; 错误操作
Runnable runnable = () -> {
// num++; 错误操作
// long num = 2; 错误操作
System.out.println(num) ;
};
new Thread(runnable).start();
}
2. 函数式接口
2.1 定义
- 函数式接口(functional interface):有且只有一个抽象方法的接口就是函数式接口。
- 函数式接口中可以定义 default、static、private 关键字修饰的非抽象方法。
- @FunctionalInterface 注解用来标记此接口为函数式接口,标记后编译器就会检查此接口是否符合函数式接口的定义,如果不符合就会编译出错。如果能保证你的接口有且只有一个抽象方法,也可以不加这个注解。
/**
* 自定义一个有参数无返回值的函数式接口
*/
interface MyFunInterface {
void abc(String s);
}
@Test
public void myTest() {
MyFunInterface mf = (x) -> System.out.println(x);
mf.abc("aabbcc"); // aabbcc
}
2.2 JDK8四种核心的函数式接口
2.2.1 供给性接口:Supplier
- 此接口不接收参数,但有返回值。抽象方法是 get 。
- 源码:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
- 示例:
不接收参数,但有返回值:
Supplier<Long> supplier = () -> System.currentTimeMillis();
Long ctm = supplier.get();
2.2.2 消费性接口:Consumer
- 此接口接收一个参数t,但没有返回值。抽象方法是 accept 。
- 源码:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
- 示例:
接收一个参数,但没有返回值:
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("123"); // 123
默认方法 andThen() 可以链式调用,将多个对象组合在一起,然后按照顺序执行:
Consumer<String> cs1 = str1 -> "123".equals(str1);
Consumer<String> cs2 = str2 -> System.out.println(str2);
cs1.andThen(cs2).accept("123"); // 123
2.2.3 功能性接口:Function
- 此接口接收一个功能参数t,并返回一个功能结果R。抽象方法是 apply 。
- 源码:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
- 示例:
接收一个参数,并返回一个结果:
Function<String,Integer> function = str -> Integer.parseInt(str);
int result = function.apply("123");
默认方法 andThen() 可以链式调用,将多个对象组合在一起,然后按照顺序执行,第1个对象执行的结果作为第二个对象的参数:
Function<String,Integer> ft1 = t1 -> Integer.parseInt(t1);
Function<Integer,Integer> ft2 = t2 -> t2 * 100;
System.out.println(ft1.andThen(ft2).apply("123")); // 12300
2.2.4 断言性接口:Predicate
- 此接口接收一个参数t,如果输入参数符合断言则返回true,否则false 。抽象方法是 test 。
- 源码:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
- 示例:
接收一个参数,如果输入参数符合断言则返回true,否则false:
Predicate<String> predicate = str -> Integer.parseInt(str) > 123;
boolean result = predicate.test("123");
3. :: 操作符
3.1 方法引用
- 引用类的静态方法格式: 类名::静态方法名,Math::pow 等价于 (x,y) -> Math.pow(x, y)。
- 引用实例对象的实例方法格式: 实例对象名::实例方法名,student::getName 等价于 () -> student.getName()。
- 引用类的实例方法格式: 类名::实例方法名,String::compareTo 等价于 (o1,o2) -> o1.compareTo(o2)。
3.2 构造器引用
构造器引用的语法格式:类名::new ,例如,Student::new 是 Student 构造器的一个引用。
示例:
@Test
public void myTest(){
// 调用无参构造函数
Supplier<Student> supplier = Student::new;
System.out.println(supplier.get()); // 学生
// 调用有参构造函数
Function<String,Student> function = Student::new;
System.out.println(function.apply("wang")); // wang
}
class Student {
public String name;
public Student() {
this.name = "学生";
}
public Student(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
4. Optional 类
- Optional 类是一个可以包含或不包含非null值的容器。如果存在值,则 isPresent() 将返回 true,而 get() 将返回该值。。
- Optional 类是一个基于值的类;在Optional实例上使用标识敏感的操作(包括引用等于(==),标识哈希码或同步)可能会产生不可预测的结果,应避免使用。
定义:
public final class Optional<T> extends Object
源码:
public final class Optional<T> {
// 如果非空,则为该值;如果为null,则表示不存在任何值
private final T value;
// 构造函数为私有构造函数
}
API:
static <T> Optional<T> empty() 返回一个空的Optional实例。
示例:
Optional optional = Optional.empty();
System.out.println(optional); // Optional.empty
boolean equals(Object obj) 表示其他某个对象是否“等于”此Optional。
源码:
Objects.equals(value, other.value) // 实际equals的是Optional实例的value。
static <T> Optional<T> ofNullable(T value) 返回描述指定值的Optional,如果为null,则返回一个空Optional。
示例:
Optional o1 = Optional.ofNullable(new String("a"));
Optional o2 = Optional.ofNullable(null);
System.out.println(o1); // Optional[a]
System.out.println(o2); // Optional.empty
T orElse(T other) 如果存在,返回该值,否则返回other。
示例:
String str = null;
str = Optional.ofNullable(str).orElse("a");
System.out.println(str); // a
T orElseGet(Supplier<? extends T> other) 如果存在,返回该值,否则调用other,然后返回该调用的结果。
示例:
String str = null;
str = Optional.ofNullable(str).orElseGet(() -> "other");
System.out.println(str); // other
String toString() 返回此Optional的字符串表示。
源码:
public String toString() {
return value != null ? String.format("Optional[%s]", value) : "Optional.empty";
}
Optional<T> filter(Predicate<? super T> predicate)
根据传入的 predicate 对 Optional 中的值进行过滤,满足条件则返回该 Optional 对象,否则返回一个空的 Optional。
示例:
Optional optional = Optional.ofNullable(1);
Predicate<Integer> predicate= num -> num > 1;
System.out.println(optional.filter(predicate)); // Optional.empty
predicate = num -> num <= 1;
System.out.println(optional.filter(predicate)); // Optional[1]
<U> Optional<U> map(Function<? super T,? extends U> mapper)
如果 Optional 存在值,则执行 mapper 映射函数返回结果,否则返回一个空的 Optional。
示例:
String str = null;
Optional optional = Optional.ofNullable(str).map((s) -> "ab");
System.out.println(optional); // Optional.empty
Optional optional2 = Optional.ofNullable("a").map((s) -> "ab");
System.out.println(optional2); // Optional[ab]
int hashCode() 如果存在值,返回当前值的哈希码值,如果没有值,则返回0(零)。
boolean isPresent() 如果存在值,则返回true,否则返回false。
void ifPresent(Consumer<? super T> consumer) 如果存在值,执行 consumer 的具体操作,否则不执行任何操作。
示例:
Optional optional = Optional.ofNullable("a");
optional.ifPresent(System.out::println); // a
5. Stream流
- 流不会储存数据。
- 流的操作不会修改其数据源。
- 流的操作是尽可能的惰性执行。也就是要等到需要结果的时候才会去执行。
API:
default Stream<E> stream()
返回当前集合中所有元素的顺序流。Collection 接口的方法。
default Stream<E> parallelStream()
返回当前集合中所有元素的并行流。Collection 接口的方法。
static <T> Stream<T> empty() 返回一个空的顺序流。
static <T> Stream<T> of(T t) 返回包含单个元素的顺序流。
static <T> Stream<T> of(T... values) 返回其元素为指定值的有序顺序流。
示例:
Stream<String> s = Stream.of("a", "b", "c");
Stream<String> ss = Stream.of("a!b!c".split("!"));
Stream<T> filter(Predicate<? super T> predicate)
返回一个包含当前流中满足 predicate 所有元素的流。
<R> Stream<R> map(Function<? super T,? extends R> mapper)
返回一个流,它包含将 mapper 应用于当前流中所有元素产生的结果。
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
返回一个流,它是通过将 mapper 应用于当前流中所有元素产生的结果连接到一起而获得的。
示例:
List<List<String>> twoList = new ArrayList<>();
List<String> ls1 = new ArrayList<>();
ls1.add("a");
ls1.add("b");
twoList.add(ls1);
List<String> ls2 = new ArrayList<>();
ls2.add("c");
ls2.add("d");
twoList.add(ls2);
List<String> list = twoList.stream().flatMap(two -> two.stream().filter(s -> !s.equals("c"))).collect(Collectors.toList());
list.forEach(System.out::print); // abd
void forEach(Consumer<? super T> action) 为此流的每个元素执行一个动作。
Stream<T> limit(long maxSize) 返回由该流前 maxSize 元素组成的流。
Stream<T> skip(long n) 返回由该流除前 n 个元素之外的元素组成的流。
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
创建一个延迟串联的流,其元素是第一个流的所有元素,然后是第二个流的所有元素。
Stream<T> distinct()
返回由当前流中所有不同元素组成的流(根据Object.equals(Object))。
Stream<T> sorted()
返回由该流的元素组成的流,并根据自然顺序排序。
Stream<T> sorted(Comparator<? super T> comparator)
返回由该流的元素组成的流,并根据提供的Comparator对其进行排序。
Stream<T> peek(Consumer<? super T> action)
返回一个流,它与当前流中的元素相同,在获取其中每个元素时,会将其传递给 action。
Optional<T> max(Comparator<? super T> comparator)
根据提供的Comparator返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator)
根据提供的Comparator返回此流的最小元素。
boolean allMatch(Predicate<? super T> predicate)
返回此流的所有元素是否与提供的predicate匹配;所有元素匹配成功,返回true
boolean anyMatch(Predicate<? super T> predicate)
返回此流的任何元素是否与提供的predicate匹配;任意一个元素匹配成功,返回true。
boolean noneMatch(Predicate<? super T> predicate)
返回此流中是否没有元素与提供的predicate匹配。
long count() 返回当前流中元素的数量。这是一个终止操作。
Object[] toArray() 返回包含此流元素的数组。
<R,A> R collect(Collector<? super T,A,R> collector)
使用收集器对此流的元素执行可变还原操作。
6. Base64、Base64.Decoder、Base64.Encoder
6.1 Base64工具提供的编码器
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
- 基本:使用RFC 4648和RFC 2045表1中指定的“Base64字母”进行编码和解码操作。编码器不添加任何换行符,解码器拒绝包含base64字母之外的字符的数据。
- URL和文件名安全:使用RFC 4648表2中指定的“URL和文件名安全的Base64字母”进行编码和解码。编码器不添加任何换行符,解码器拒绝包含base64字母之外的字符的数据。
- MIME:使用RFC 2045表1中指定的“Base64字母”进行编码和解码操作。编码后的输出必须以不超过76个字符的行表示,并使用回车符’\r’和紧跟换行符’\n’作为行分隔符,编码输出的末尾没有行分隔符。在base64字母表中找不到的所有行分隔符或其他字符在解码操作中将被忽略。
6.2 获取Base64编码器或解码器
1、获取Base64编码器
Base64.Encoder encoder = Base64.getEncoder();
Base64.Encoder urlEncoder = Base64.getUrlEncoder();
Base64.Encoder mimeEncoder = Base64.getMimeEncoder();
2、获取Base64解码器
Base64.Decoder decoder = Base64.getDecoder();
Base64.Decoder urlDecoder = Base64.getUrlDecoder();
Base64.Decoder mimeDecoder = Base64.getMimeDecoder();
6.3 Base64编码解码示例
try {
byte[] bt = "A-Za-z0-9+/_编码".getBytes("utf-8");
// 编码
Base64.Encoder encoder = Base64.getEncoder();
Base64.Encoder urlEncoder = Base64.getUrlEncoder();
Base64.Encoder mimeEncoder = Base64.getMimeEncoder();
String encoderStr = encoder.encodeToString(bt); // QS1aYS16MC05Ky9f57yW56CB
String urlEncoderStr = urlEncoder.encodeToString(bt); // QS1aYS16MC05Ky9f57yW56CB
String mimeEncoderStr = mimeEncoder.encodeToString(bt); // QS1aYS16MC05Ky9f57yW56CB
// 解码
Base64.Decoder decoder = Base64.getDecoder();
Base64.Decoder urlDecoder = Base64.getUrlDecoder();
Base64.Decoder mimeDecoder = Base64.getMimeDecoder();
String decoderStr = new String(decoder.decode(encoderStr), "utf-8"); // A-Za-z0-9+/_编码
String urlDecoderStr = new String(urlDecoder.decode(urlEncoderStr), "utf-8"); // A-Za-z0-9+/_编码
String mimeDecoderStr = new String(mimeDecoder.decode(mimeEncoderStr), "utf-8"); // A-Za-z0-9+/_编码
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}