函数式编程小分享

Posted 云户

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数式编程小分享相关的知识,希望对你有一定的参考价值。


函数式编程小分享


近期发现有不少小伙伴对于lambda以及函数式编程不太熟悉,今天把之前的一些小demo分享给大家。

JDK8接口特性

新增接口默认default的类型方法实现,可以方便接口扩展和升级

///只有一个要实现的方法的接口 适合使用lambda表达式实例化
@FunctionalInterface //函数式接口注释 最好要加,方便编译器检查语法 思想是一个接口只做一个事情
interface Intfce{
    int doubleNum(int i);
    //jdk8新增 默认实现接口方法 可以不在实现类中实现
    default int add(int x,int y){
        return x+y;
    }
}

函数式接口

@FunctionalInterface
interface FormartMoney{
    String formartMoney(int money);
}
class  MyMoney {
     private final int money;

    MyMoney(int money) {
        this.money = money;
    }
    void printMyMoney(FormartMoney formartMoney){
        System.out.println("我的钱:"+formartMoney.formartMoney(this.money));
    }
}
public class LambdaDemo2 {
    public static void main(String[] args) {
        MyMoney myMoney = new MyMoney(999999);
        myMoney.printMyMoney(i->{
            return new DecimalFormat("#,###").format(i);
        });

    }
}

jdk自带的接口

image-20210507202727054
public class Testlambda {
    /**
     * 消费型接口
     */

    @Test
    public void test1(){
        happy(2000,m->System.out.println("打车消费了"+m+"元"));
    }
    public void happy(double money, Consumer<Double> consumer){
        consumer.accept(money);
    }
    /**
     * 供给型接口
     */

    @Test
    public void test2(){
        sup(10, ()->(int)(Math.random()*100)).forEach(e->System.out.println(e));
    }
    public List<Integer> sup(int size, Supplier<Integer> supplier){
        List<Integer> list=new ArrayList<>();
        for (int i=0;i<size;i++){
            list.add(supplier.get());
        }
        return list;
    }
    /**
     * 函数型接口
     */

    @Test
    public void test3(){
        System.out.println(dealStr("我去你大2222爷",x->x.length()));
    }
    public Integer dealStr(String s, Function<String,Integer> function){
        return function.apply(s);
    }
    /**
     * 断言型接口
     */

    @Test
    public void test4(){
        List<String> list = Arrays.asList("李四","张三","王五");
        judgeInList(list,x->x.contains("李")).forEach(System.out::println);
    }
    public List<String> judgeInList(List<String> list,Predicate<String> predicate){
        List<String> list1=new ArrayList<>();
        list.forEach(s -> {
            if(predicate.test(s)){
                list1.add(s);
            }
        });
        return list1;
    }
}

方法引用

比较简单,一看就明白了

List<String> list = Arrays.asList("李四","张三","王五");
list.forEach(System.out::println);

//构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
 final Car car = Car.create( Car::new );
 final List< Car > cars = Arrays.asList( car );
 //静态方法引用:它的语法是Class::static_method,实例如下:
 cars.forEach( Car::collide );
 //特定类的任意对象的方法引用:它的语法是Class::method实例如下:
 cars.forEach( Car::repair );
//特定对象的方法引用:它的语法是instance::method实例如下:
 final Car police = Car.create( Car::new );
 cars.forEach( police::follow );

变量引用

匿名类引用外边的变量必须是final,其实JDK8里也是没有变,只是可以省略final关键字,但是还是要求该变量为实际final类型

@FunctionalInterface
interface IntfceVar{
    void doubleNum(int i);
}
public class VarDemo {
    public static void main(String[] args) {
        String ss = "asda";
//        ss="2222";//当去掉注释会报错
        IntfceVar intfceVar = s-> System.out.println(ss);

    }
}

思考为什么内部类引用外部变量必须是final?

由于java引用是传值,而不是传引用(这个话可能理解存在差异),以下代码为例

public class VarDemo {
    public static void main(String[] args) {
        List<String> ss = new ArrayList<>();//这里ss指向 new ArrayList<>()的实例地址
//        ss=new ArrayList<>();//当去掉注释会报错
        IntfceVar intfceVar = s-> System.out.println(ss);//这里ss 也是指向上边实例的地址,但是当ss改变时,实际指向了新的对象实例地址,而由于实际运行时,字节码执行的顺序问题,可能导致匿名内部类中的方法执行的对象与实际的对象指引有差异。因此java做了这样的限制。

    }
}

级联表达式和柯里化

级联表达式

就是有多个箭头的lambda表达式

public class CurryDemo {
    public static void main(String[] args) {
        x->y-> x + y; //当然目前是报错的
    }
}
public class CurryDemo {
    public static void main(String[] args) {
       Function<Integer,Function<Integer,Integer>> functionFunction = x-> y-> x + y;//编译成功
        System.out.println(functionFunction.apply(2).apply(3));//输出5
    }
}

柯里化

那么柯里化是什么?

把多个参数的函数,转化为只有一个参数的函数,这个就叫做柯里化

如上的级联表达式。

目的

函数标准化

显而易见,函数的参数是固定一个

批量处理

Function<Integer,Function<Integer,Function<Integer,Integer>>> fun2 = x-> y-> z-> x + y+z;
        
        int[] nums={2,3,4};
        Function f = fun2;
        for (int i = 0; i < nums.length; i++) {
            if(f instanceof Function){
                Object obj = f.apply(nums[i]);
                if(obj instanceof  Function){
                    f = (Function)obj;
                }else{
                    System.out.println("最终结果:"+obj);
                }
            }
        }

高阶函数

返回函数的函数

后续还有stream、响应式编程会分享给大家,尽情期待。


以上是关于函数式编程小分享的主要内容,如果未能解决你的问题,请参考以下文章

Js模型和封装(没毕业的孩子,一点拙劣的小分享,欢迎批评和补充)

代码片段如何使用CSS来快速定义多彩光标

知识小分享

unity3d俯视角简易移动控制脚本及其易错点小分享

运维小分享整理Apache日志

初学LINUX,一些自己的小分享