• java语言基础4--lambda表达式


      lambda表达式的的本质是匿名方法。但是这个方法不是不是独立执行的,而是用于实现函数式接口定义的方法,因此lambda表达式会产生一个匿名类,lambda表达式通常也被称为闭包。

      函数式接口是仅仅包含一个方法的接口,这个方法指明了接口的用途,所以函数式接口通常表示单个动作,比如Runnable接口就是一个标准的函数式接口,因为它只定义了一个run方法。此外函数式接口可以指定Object的任何共有方法,Object的lambda表达式的隐式成员,函数式接口的实例会默认实现它们。

       lambda表达式的基本知识

        () -> 123.45;  () -> {return 123.45};    (n) ->  (n%2) ==0; 

      以上三种情况是典型的简单的lambda表达式体,当参数只有一个的时候    () 也可以去掉

    public interface MyNum {
        byte getValue(int a,int b);
    }
    public class AAA {
        public static void main(String[] args) {
            //这里的 int 可以省略,可以从上下文推断出来
            MyNum myNum = (int m,int n)->{
                return (byte) (m+n);
            };
            System.out.println(myNum.getValue(5, 4));//输出9
        }
    }

      以上是代码块类型的lambda块,代码块里面必须要写return,这个return 只是返回lambda体,不会导致lambda外部的方法返回。

      函数式接口可以是泛型的 如下:

    public interface MyDouble<RETURN,PARAM> {
        RETURN getValue(PARAM P);
    }
    public class AAA {
        public static void main(String[] args) {
            MyDouble<Integer, Integer> md =(a) ->  a+5;
            System.out.println(md.getValue(1));//6
    
            MyDouble<String, Integer> md1 =(a) ->  (a+5)+" is a String";
            System.out.println(md1.getValue(1));//6 is a String
        }
    }

       lambda作为参数传递

      为了将lambda表达式作为参数传递,接受表达式的参数类型必须与该lambda表达式的函数式接口兼容

    public interface TestFuncParam {
     String func(String str);
    }
    public class BBB {
        static String stringOP(TestFuncParam t,String s) {
            return t.func(s);
        }
        public static void main(String[] args) {
            String instr = "bbb";
            String outStr;
            //这里创建一个函数式接口TestFuncParam的一个实例
            TestFuncParam aa = (str)->{
                return str.toUpperCase();
            };
            //将实例 传递给stringOP方法参数中 并调用
            outStr = stringOP(aa, instr);
            System.out.println(outStr);//输出BBB
        }
    }

       lambda表达式的异常

      lambda表达式可以抛出异常,但是抛出经检查的异常时,该异常就必须与函数式接口的抽象方法声明的异常兼容,

    public interface DoubleParam {
        double func(double[] arr) throws EmptyArrException;
    }
    public class EmptyArrException extends Exception {
        EmptyArrException(){
            super("ARRAY EMPTY");
        }
    }
    public abstract class Test {
        public static void main(String[] args) throws Exception{
            double [] arr = {1.1,1.2,1.3};
            double [] arr1 = {};
            DoubleParam first = (arr2)->{
                if(arr2.length==0) {
                    throw new EmptyArrException();
                }else {
                    return arr2[0];
                }
            };
            System.out.println(first.func(arr));//输出1.1
            System.out.println(first.func(arr1));//报异常
        }
    }

       lambda表达式的变量捕获

      lambda表达式可以访问其外层类的实例,静态变量或者方法,但是当访问外层作用域内定义的局部变量时,会产生变量捕获的情况,lambda表达式实质上只能访问外层作用域的final变量(和匿名方法一样),因此一旦lambda表达式引用了外层作用域的变量,不管该变量是否显式的声明为final,该变量实际上已经成为final变量了,所以该变量是不能被修改的(不管是lambda表达式体内还是体外)

    public interface MyFunc {
        int func(int n);
    }
    public class TestFunc {
        private  int constT = 1; 
        public static void main(String[] args) {
            TestFunc testFunc = new TestFunc();
            int num = 10;
            MyFunc fun = (n) -> {
                System.out.println(++testFunc.constT);//合法 输出2
                int v = n+num;
    //            num++;   //不合法  final变量不能修改
                return v;
            };
            System.out.println(fun.func(10)); //输出20
    //        System.out.println(num++); //不合法  final变量不能修改
        }
    }

     方法引用

      静态方法引用  语法为 ClassName::methodName

    public interface StringFunc {
        String func(String str);
    }
    public class Test {
        static String reverse(String str) {
            return str.toUpperCase();
        }
        static String StringOps(StringFunc func,String str) {
            return func.func(str);
        }
        
        public static void main(String[] args) {
            String in = "aaaaa";
            String out = StringOps(Test::reverse, in);
            System.out.println(out);
        }
    }

      实例方法的引用 语法为 objRef::methodName

    public interface StringFunc {
        String func(String str);
    }
    public class Test {
        String reverse(String str) {
            return str.toUpperCase();
        }
        static String StringOps(StringFunc func,String str) {
            return func.func(str);
        }
        
        public static void main(String[] args) {
            String in = "aaaaa";
            Test test = new Test();
            String out = StringOps(test::reverse, in);
            System.out.println(out);
        }
    }

      下面的实例方法引用或许更加方便,只需指定类名和方法名,无需指定对象,其语法为ClassName::instaceName

    public interface MyFunc<T> {
        boolean func(T v1,T v2);
    }
    public class HighTemp {
        private int hTemp;
        
        HighTemp(int ht){
            this.hTemp = ht;
        }
        
        boolean sameTemp(HighTemp ht) {
            return hTemp==ht.hTemp;
        }
        
        boolean lessThanTemp(HighTemp ht) {
            return hTemp<=ht.hTemp;
        }
    }
    public class Test {
        static <T> int counter(T[] vals,MyFunc<T> f,T v) {
            int count =0;
            for(int i=0;i<vals.length;i++) {
                if(f.func(vals[i], v)) {
                    count++;
                }
            }
            return count;
        }
        
        public static void main(String[] args) {
            int count ;
            HighTemp[] weekDayHigh = {new HighTemp(50),new HighTemp(50),new HighTemp(50),new HighTemp(50),
                                      new HighTemp(1),new HighTemp(99),new HighTemp(99),new HighTemp(99),};
            count = counter(weekDayHigh, HighTemp::sameTemp, new HighTemp(50));
            System.out.println(count);//输出4
            
            count = counter(weekDayHigh, HighTemp::lessThanTemp, new HighTemp(1));
            System.out.println(count);//输出1
        }
    }

      泛型中的方法引用

      在泛型类或者泛型方法中也可以使用方法引用

    public interface MyFunc<T> {
        int func(T[] vals,T v2);
    }
    public class MyArrOps {
        static <T> int countMatch(T[] vals,T v) {
            int count =0;
            for(int i=0;i<vals.length;i++) {
                if(vals[i]== v) {
                    count++;
                }
            }
            return count;
        }
    }
    public class Test {
        
        static <T> int myOp(T[] vals,MyFunc<T> f,T v) {
            return f.func(vals, v);
        }
        
        public static void main(String[] args) {
            Integer [] arr1 = {1,2,3,4,4};
            String [] arr2 = {"1","2","3","4"};
            //这里的<Integer> 也可以省略,可以从上下文自动推断出来
            int count = myOp(arr1, MyArrOps::<Integer>countMatch, 4);//输出2
            System.out.println(count);
            
            int count1 = myOp(arr2, MyArrOps::<String>countMatch, "4");//输出1
            System.out.println(count1);
        }
    }

      方法引用lambda  真正的优势在于和集合一起使用,下面举一个例子,实现获取集合中最大的数,之前的做法是传递一个集合对象和Comparator<T>,并重写compare()方法,下面使用lambda实现

    public class MyClass {
        private int val;
        
        MyClass(int val){this.val = val;}
        
        public int getVal() {return val;}
        
        public void setVal(int val) {this.val = val;}
    }
    public class Test {
        static int compareMC(MyClass c1,MyClass c2) {
            return c1.getVal()-c2.getVal();
        }
        
        public static void main(String[] args) {
            List<MyClass> list= new ArrayList<>();
            list.add(new MyClass(1));
            list.add(new MyClass(2));
            list.add(new MyClass(3));
            list.add(new MyClass(4));
            list.add(new MyClass(4));
            MyClass maxClass = Collections.max(list, Test::compareMC);
            System.out.println(maxClass.getVal());//输出4
        }
    }

      构造方法引用  语法为ClassName::new

    public interface MyFunc {
        MyClass func(int n);
    }
    public class MyClass {
        private int val;
        
        MyClass(int val){this.val = val;}
    
        public int getVal() {return val;}
    
        public void setVal(int val) {this.val = val;}
    }
    public class Test {
        public static void main(String[] args) {
            MyFunc mf1 = MyClass::new;
            MyClass mc = mf1.func(11);
            System.out.println(mc.getVal());//输出11
        }
    }

     也可将上面的例子改成泛型版本的

    public interface MyFunc<R,T> {
        R func(T t);
    }
    public class MyClass<T> {
        private T val;
        
        MyClass(T t){val=t;}
    
        public T getVal() {return val;}
    
        public void setVal(T val) {this.val = val;}
        
    }
    public class Test {
        static<R,T> R myClassFactory( MyFunc<R,T> func,T t) {
            return func.func(t);
        }
        public static void main(String[] args) {
            MyFunc<MyClass<Integer>, Integer> func1 =MyClass<Integer>::new;
            MyClass<Integer> class1 = myClassFactory(func1, 100);
            System.out.println(class1.getVal());//输出100
            
            MyFunc<MyClass<String>, String> func2 =MyClass<String>::new;
            MyClass<String> class2 = myClassFactory(func2, "I am a String");
            System.out.println(class2.getVal());//输出I am a String
        }
    }

      以上的所有例子都定义了一个函数式接口,但我们很多时候并不需要自己定义这个接口,JDK8提供了java.util.function和java.util.stream包提供了一些预定义的函数式接口,后面我们将讨论他们,以下是它们的一些简介。

      下面使用预定义函数式接口Function 来实现lambda。

    public class Test {
        public static void main(String[] args) {
            Function<Integer, String> function = (n)->{
                return n.toString()+" is a number";
            };
            String result = function.apply(100);
            System.out.println(result);//输出  100 is a number
        }
    }

     -------------------------------------------以下是常用的lambda使用例子和第二部分的lambda的使用-------------------------------------------------

    https://www.cnblogs.com/franson-2016/p/5593080.html

  • 相关阅读:
    jedis异常:Could not get a resource from the pool
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resourc
    【redis】常见JedisConnectionException异常分析
    JAVA,字符串首字母转大写(高效率)
    Type handler was null on parameter mapping for property 'products'. It was either not specified and/or could not be found for the javaType / jdbcType combination specified
    java读取blob,clob转换为字符串
    mybatis对blob属性数据的处理
    mybatis读取oracle中blob
    jpa2.x的getOne()/findOne()/findById()的区别及使用
    IDEA如何导入导出出settings配置文件
  • 原文地址:https://www.cnblogs.com/tjqBlog/p/9774686.html
Copyright © 2020-2023  润新知