Java常见问题的简单解法
提示:总结于LeetCode书籍《Java常见问题的简单解法》,全书其实就是用Stream去通过函数式编程,更加简洁,快速,高效的解决实际问题。
第二章 Java.util.function 包
一、Consumer接口
Consumer接口定义:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
该接口为函数式接口,拥有单一抽象方法,同时拥有一个用于复合操作的默认方法。
Iterable接口定义的forEach:
default void forEach(Consumer<? super T> action)
其中Consumer作为foreach的参数,所以我们在调用Iterable的foreach方法时,.可用lambda表达式。举个栗子:
List<String> strings = Arrays.asList("this", "is", "a", "list", "of", "strings");
//匿名内部类实现
strings.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//lambda表达式
strings.forEach(s -> System.out.println(s));
//方法引用
strings.forEach(System.out::println);
二、Supplier接口
Supplier接口定义:
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
可以看出该接口只有一个get抽象方法,返回类型为传入的类型。我们可以用它来创建我们需要的对象(可以理解为一个可以创建对象的工厂)。
举个栗子:
//创建String对象
Supplier<String> name = String::new;
//创建Person对象
Supplier<Person> person = Person::new;
三、Predicate接口
Predicate接口定义:
@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);
}
}
Predicate接口主要用于流的删选。Stream接口的filter方法传入Predicate并返回一个新的流。
Steam接口的filter方法定义源码:
Stream<T> filter(Predicate<? super T> predicate);
接下来列举一些使用fileter的栗子:
//查找具有给定长度的字符串
public String getNamesOfLength(int length, String... names) {
return Arrays.stream(names)
.filter(s -> s.length() == length) ➊
.collect(Collectors.joining(", "));
}
//查找以给定字符串开头的字符串
public String getNamesStartingWith(String s, String... names) {
return Arrays.stream(names)
.filter(str -> str.startsWith(s)) ➊
.collect(Collectors.joining(", "));
}
//查找满足任意谓语动词的字符串
public class ImplementPredicate {
public String getNamesSatisfyingCondition(
//这里Predicate<T>作为参数,参数里面的条件可以自由定义,如:
//满足字符串长度为5可写为:public static final Predicate<String> LENGTH_FIVE = s -> s.length() ==5;
//满足字符串开头为5可以写为: public static final Predicate<String> STARTS_WITH_S =
s -> s.startsWith("S");
Predicate<String> condition, String... names) {
return Arrays.stream(names)
.filter(condition) ➊
.collect(Collectors.joining(", "));
}
}
使用谓语动词还可以将and,or,negate组合用起来。
Predicate.and();俩个条件都满足
public void whenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){
Predicate<String> predicate1 = str -> str.startsWith("A");
Predicate<String> predicate2 = str -> str.length() < 5;
List<String> result = names.stream()
.filter(predicate1.and(predicate2))
}
Predicate.or():满足其中一个条件
public void whenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){
Predicate<String> predicate1 = str -> str.startsWith("J");
Predicate<String> predicate2 = str -> str.length() < 4;
List<String> result = names.stream()
.filter(predicate1.or(predicate2))
.collect(Collectors.toList());
}
Predicate.negate();取反
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){
Predicate<String> predicate1 = str -> str.startsWith("J");
Predicate<String> predicate2 = str -> str.length() < 4;
List<String> result = names.stream()
.filter(predicate1.or(predicate2.negate()))
.collect(Collectors.toList());
}
当然,在我们平时遇到需要过滤多个条件是也可以直接拼接,无需先定义好Predicate。
public void whenFilterListWithMultipleFilters_thenSuccess(){
List<String> result1 = names.stream()
.filter(name -> name.startsWith("A"))
.filter(name -> name.length() < 5)
.collect(Collectors.toList());
List<String> result2 = names.stream()
.filter(name -> name.startsWith("A") && name.length() < 5)
.collect(Collectors.toList());
}
四、Function接口
Predicate接口定义:
@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接口包含单一抽象方法apply,他可以将T类型的泛型输入参数转换为R类型的泛型输出值。
Function最常见的用法是作为Stream.map方法的一个参数,例如,为了将string转换为整数,可以在每个实例上调用length方法。举个栗子:
//讲字符串映射到他们的长度
List<String> names = Arrays.asList("Mal", "Wash", "Kaylee", "Inara",
"Zoë", "Jayne", "Simon", "River", "Shepherd Book");
//匿名内部类实现
List<Integer> nameLengths = names.stream()
.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
})
.collect(Collectors.toList());
//lambda实现
nameLengths = names.stream()
.map(s -> s.length())
.collect(Collectors.toList());
//方法引用
nameLengths = names.stream()
.map(String::length)
.collect(Collectors.toList());