常用函数式接口
Predicate
Predicate接口的test方法,接收一个参数,返回一个布尔值。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T var1);
}
举例:
先看个简单的例子:判断字符串长度是否大于5
public class LambdaTest {
public static void main(String[] args) {
//Predicate接收一个参数,返回布尔值
Predicate<String> predict = (String str) -> { return str.length() > 5; };
System.out.println(predict.test("hello"));
System.out.println(predict.test("welcome"));
}
}
输出:
false
true
再看一个例子,有一个Apple集合,现在要筛选出红色的苹果
public class Apple {
private String category;
private String color;
private double weight;
public Apple(String category, String color, double weight) {
this.category = category;
this.color = color;
this.weight = weight;
}
// getter and setter and toString
}
public class LambdaTest {
public static void main(String[] args) {
Apple apple1 = new Apple("红星", "Red", 280);
Apple apple2 = new Apple("黄元帅", "Yello", 470);
Apple apple3 = new Apple("红将军", "Red", 320);
Apple apple4 = new Apple("国光", "Green", 300);
List<Apple> appleList = Arrays.asList(apple1, apple2, apple3, apple4);
//filter方法接收一个Predicate类型的参数
appleList.stream().filter(apple -> "Red".equals(apple.getColor()))
.forEach(apple -> System.out.println(apple));
}
}
输出:
Apple{category='红星', color='Red', weight=280.0}
Apple{category='红将军', color='Red', weight=320.0}
- stream 是Collection的一个方法,将集合转换成流。
- filter是stream的一个方法表示过滤。
- forEach是Iterable的方法,迭代处理。
我们先不关注stream、filter、forEach方法,主要关注filter方法的参数,它接收一个Predict类型的参数,Predict,接收一个参数,返回一个布尔值,
apple -> “Red”.equals(apple.getColor()): 一个输入参数,返回布尔值,符合Predict接口定义。如果需要筛选出红色的,重量大于300克的苹果,方法如下:
appleList.stream().filter(apple -> "Red".equals(apple.getColor()) && (300 < apple.getWeight()))
.forEach(apple -> System.out.println(apple));
//或者(filter方法返回的还是Stream)
appleList.stream().filter(apple -> "Red".equals(apple.getColor()))
.filter(apple -> 300 < apple.getWeight())
.forEach(apple -> System.out.println(apple));
Supplier
Supplier 不接收参数,返回一个值。
@FunctionalInterface
public interface Supplier<T> {
T get();
}
举例:返回一个随机int值:() -> new SecureRandom().nextInt(20) 符合不接收参数,返回一个值的定义
public class LambdaTest {
public static void main(String[] args) {
Supplier<Integer> randomInt = () -> new SecureRandom().nextInt(20);
System.out.println(randomInt.get());
}
}
BinaryOperator
BinaryOperator 接口继承自BiFunction,接收两个参数,返回一个值,与BiFunction不同的是,它的两个输入参数和返回值都是同一种类型。其实第二节的四则运算的例子用BinaryOperator实现更为方便。
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T, T, T> {
static default <T> BinaryOperator<T> minBy(Comparator<? super T> var0) {
Objects.requireNonNull(var0);
return (var1, var2) -> {
return var0.compare(var1, var2) <= 0?var1:var2;
};
}
static default <T> BinaryOperator<T> maxBy(Comparator<? super T> var0) {
Objects.requireNonNull(var0);
return (var1, var2) -> {
return var0.compare(var1, var2) >= 0?var1:var2;
};
}
}
举例:
public class LambdaTest {
public static void main(String[] args) {
Integer num1 = 16, num2 = 2;
MyCalculator<Integer> calculator = new MyCalculator<>();
System.out.println(calculator.comput(num1, num2, (n1, n2) -> n1 + n2));
System.out.println(calculator.comput(num1, num2, (n1, n2) -> n1 - n2));
System.out.println(calculator.comput(num1, num2, (n1, n2) -> n1 * n2));
System.out.println(calculator.comput(num1, num2, (n1, n2) -> n1 / n2));
}
}
class MyCalculator<T> {
public T comput(T t1, T t2, BinaryOperator<T> binaryOperator) {
return binaryOperator.apply(t1, t2);
}
}
输出:
18
14
32
8
我们看到BinaryOperator有两个静态方法minBy,maxBy,这两个静态方法返回一个BinaryOperator结果,这个BinaryOperator的返回值是根据minBy的参数Comparator来决定的。
public class LambdaTest {
public static void main(String[] args) {
//返回一个BinaryOperator对象
BinaryOperator<String> binaryOperator = BinaryOperator.minBy((str1, str2) -> str1.compareTo(str2));
//BinaryOperator返回的结果,是有minBy的参数Comparator决定的,也就是比较大小,取较小的那个字符串
System.out.println(binaryOperator.apply("hello", "abcdef"));
}
}
输出:
abcdef
BiConsumer
接收两个参数,不返回值
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
举例:
(key, value) -> System.out.println(key + ” : ” + value)
接收两个参数,不返回值,符合BiConsumer定义
public class LambdaTest {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>(2);
map.put("java8", "netty");
map.put("jvm", "nodejs");
map.put("hbase", "spring");
map.forEach((key, value) -> System.out.println(key + " : " + value));
}
}
输出:
jvm : nodejs
java8 : netty
hbase : spring
以上就是常用的函数式接口,函数式接口还是很容易理解和使用的,函数式接口可以用lambda表达式来创建,之前的例子中,都是用的是常规的,符合标准形式(或简写)的lambda表达式。下一节介绍方法引用。
(Type1 param1, Type2 param2......) -> { body }
Optional
Optional是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
可以类比基本数据类型的包装类,Optional可以包装任何值,并且可以通过isPresent()判断是否值存在
public class OptionalTest {
public static void main(String[] args) {
Optional<String> optional = Optional.of("optional");
if(optional.isPresent()){
System.out.println(optional.get());
}
}
}
输出:
optional
上面的例子并不是推荐的写法,因为上面的这种写法和之前的写法没有本质区别:
public class OptionalTest {
public static void main(String[] args) {
String str = "optional";
if(null != str){
System.out.println(str);
}
}
}
输出:
optional
推荐的写法如下:
public static void main(String[] args) {
Optional<String> optional = Optional.of("optional");
//为空则不做任何操作
optional.ifPresent(System.out::println);
}
}
输出:
optional
orElse 如果Optional包装的值为空,用默认值来替代
public class OptionalTest {
public static void main(String[] args) {
//创建一个包装了空值的Optional
Optional<String> optional = Optional.empty();
//为空则用默认值替代
System.out.println(optional.orElse("java8"));
}
}
输出:
java8
orElseGet 或者如果Optional包装的值为空,提供一个Supplier,从Supplier获取值
public class OptionalTest {
public static void main(String[] args) {
//创建一个包装了空值的Optional
Optional<String> optional = Optional.empty();
//为空则使用用户提供的Supplier获取值
System.out.println(optional.orElseGet(()->"hello world"));
}
}
输出:
hello world
Optional.of(object) object一定不能为空,如果不能确定object是否为空,可以用Optional.ofNullable(object)
不要将Optional做为方法的参数,或者类的成员变量,Optional没有实现序列化,Optional一般只做为方法的返回值。