函数式编程
函数式编程强加了额外的约束,即所有数据必须是不可变的:设置一次,永不改变。将值传递给函数,该函数然后生成新值但从不修改自身外部的任何东西,不可变对象和无副作用范式解决了并发编程中最基本和最棘手的问题之一。
Lambda表达式只支持函数式接口,也就是只有一个抽象方法的接口
普通用法和函数式编程对比
@FunctionalInterface //用于判断是否符合函数式接口
public interface Interf {
String f(String msg);
}
public class InterfImpl implements Interf {
@Override
public String f(String msg) {
return msg + " 普通实现";
}
static String func(String msg) {
return msg + " 方法引用";
}
public static void main(String[] args) {
Interf[] interfs = new Interf[]{
new InterfImpl(),//普通实现
new Interf() {
@Override
public String f(String msg) {
return msg + " 匿名内部类";
}
},//匿名内部类
msg -> msg + " lambda", //lambda表达式
InterfImpl::func //方法引用
};
for(Interf interf : interfs){
System.out.println(interf.f("测试lambda"));
}
}
}
lambda表达式
lambda表达式,由箭头->分隔开参数和函数体,箭头左边是参数,右边是lambda返回的表达式,即函数体
lambda表达式就是函数式接口的实例
-
当只有一个参数,可以不用括号() -
如果没有参数,必须使用()表示空参数列表 -
对于多个参数,将参数列表放在括号()中 -
如果有多行,需要将这些行放在花括号,在这种情况下,需要使用return
四个内置函数式接口
Consumer 消费型接口
定义了一个accept方法,如果需要访问类型T的对象,并对其执行某些操作,可以使用这个接口
@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); };
}
}
public static void testConsumer(){
Consumer<Double> consumer = d -> System.out.println("花费"+d+"元");
consumer.accept(1000d);
}
Supplier 供给型接口
@FunctionalInterface
public interface Supplier<T> {
T get();
}
public static void testSupplier(){
Supplier<Integer> supplier = () -> {
return 100;
};
System.out.println(supplier.get());
}
Function 函数型接口
定义了一个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;
}
}
public static void testFunction(){
Function<Integer,Integer> function = x -> {
return x*100;
};
System.out.println(function.apply(10));
}
Predicate 断言型接口
定义了一个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);
}
}
public static void testPredicate(){
Predicate<String> predicate = x -> {
return "yes".equals(x);
};
System.out.println(predicate.test("no"));
}
递归
递归的Lambda表达式,递归方法必须是实例变量或静态变量。
计算阶乘
@FunctionalInterface
public interface IntCall {
int call(int i);
}
public class Recursion {
private IntCall intCall;
public static void main(String[] args) {
Recursion recursion = new Recursion();
recursion.intCall = n -> n == 0 ? 1 : n * recursion.intCall.call(n - 1);
for (int i = 0; i < 10; i++)
System.out.println(i+"! = "+recursion.intCall.call(i));
}
}
方法引用
java8的方法引用,由::区分,在::左边是类或对象的名称,在::的右边是方法的名称,但是没有参数列表
如果lambda体的内容有方法已经实现了,可以使用方法引用
Apple::getWeight 该表示方式其实是 (Apple a) -> a.getWeight()的快捷写法
方法引用其实也是lambda表达式,要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同
三种语法格式 1、对象::实例方法,指向现有对象的实例方法引用 2、类::静态方法,指向静态方法的方法引用 3、类::实例方法,指向任意类型实例方法的方法引用 当lambda表达式第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用
public class TestMethodRef {
/**
* 对象::实例方法
*/
public static void test1(){
Consumer<String> con = System.out::println;
con.accept("aaaa");
}
/**
* 类::静态方法
*/
public static void test2(){
Consumer<String> con = TestMethodRef::testStatic;
con.accept("xxxx");
}
/**
* 类::实例方法
*/
public static void test3(){
MyTest myTest = String::equals;
}
/**
* 测试无参构造器
* @return
*/
public static TestMethodRef test4(){
Supplier<TestMethodRef> supplier = TestMethodRef::new;
return supplier.get();
}
/**
* 测试有参构造器
* @return
*/
public static TestMethodRef test5(){
Function<Integer,TestMethodRef> function = TestMethodRef::new;
return function.apply(10);
}
public TestMethodRef(){
System.out.println("无参构造器调用");
}
private int x;
public TestMethodRef(int x){
this.x = x;
}
public static void main(String[] args) {
test1();
test2();
test3();
test4();
TestMethodRef t = test5();
System.out.println(t.x);
}
public static void testStatic(String x){
System.out.println("我输出入了"+x);
}
}
@FunctionalInterface
interface MyTest{
boolean test(String x,String y);
}