lambda表达式
什么是lambda
学习lamdba有两个结构十分关键,一个是lamdba自己,另一个是函数式接口
lamdba
- lamdba表达式本质上就是匿名方法,不能独立运行
- 用于实现函数式接口定义的另一个方法,因此lamdba会产生一个匿名类
- lamdba也常被称作闭包
- 引入了新的语法操作符 ->
函数式接口
- 只包含一个抽象方法的接口,这个方法说明了这个接口的意义和使用
- 函数式接口通常表示单个动作
- 有时被称作SAM类型,单抽象方法
lambda表达式示例
interface MyNumber{double getValue();
}
public static void main(String[] args){MyNumber myNum;myNum = ()-> 3.1415;System.out.println(myNum.getValue())
}//输出
3.1415
块lambda
- 处理简单的赋值等操作可以使用单个表达式
- 处理复杂的语句可以使用块lambda,可以使用多条语句
- 最后必须显示的使用return 返回值
块lambda 阶乘示例
interface MyNum{int func(int n);
}
public void test1(){MyNum mm = (n)->{int result =1;for(int i=1;i<=n;i++){result *= i;}return result;};System.out.println(mm.func(4));}
泛型函数式接口
示例
interface SomeFunc<T>{T func(T t);
}
public void test2(){SomeFunc<Integer> num = (n)-> n*10;SomeFunc<String> str = (s)-> "hello " + s;System.out.println(num.func(10));System.out.println(str.func("tom"));}
当作参数传递
interface SomeFunc<T>{T func(T t);
}
public String getResult(SomeFunc<String> some,String str){return some.func(str);}
public void test3(){String str = "hello java for lambda";String ret = getResult((n)->{return n.toUpperCase();},str);System.out.println(ret);String ret1 = getResult((n)->{return new StringBuffer(str).reverse().toString();},str);System.out.println(ret1);}
//输出
HELLO JAVA FOR LAMBDA
adbmal rof avaj olleh
lambda 表达式与异常
- lambda可以抛出异常
- 异常必须和函数式接口throws抛出的异常一致
代码示例
interface DoubleNumberFun{double fun(double[] n)throws DoubleNumberException;
}
class DoubleNumberException extends Exception{public DoubleNumberException(){super("array empty");}
}
public void test4() throws DoubleNumberException {DoubleNumberFun df = (n)->{if(n.length == 0)throw new DoubleNumberException();double sm = 0.0;for(int i=0;i<n.length;i++){sm += n[i];}return sm;};System.out.println(df.fun(new double[]{1.0,2.0,3.0}));System.out.println(df.fun(new double[]{}));}
//输出//6.0
//com.bai.lambda.DoubleNumberException: array empty
lambda 表达式变量捕获
- lambda 中可以显示或者隐式的使用this
- 使用局部变量默认是final 修饰,不能改变,不管有没有使用final。否则会提示Variable used in lambda expression should be final or effectively final
代码示例
interface MyNum{int func(int n);
}
int variable = 10;public void test5(){int variable1 = 0;MyNum m = (n)->{int sum = 0;for(int i=0;i<n;i++){sum += i + variable1;}//此处报错//Variable used in lambda expression should be final or effectively final//variable1 = sum;return sum;};MyNum m1 = (n)->{int sum = 0;for(int i=0;i<n;i++){//Variable used in lambda expression should be final or effectively finalsum += i + this.variable;}this.variable = sum;return sum;};}
方法引用
静态方法引用
- 形式: classname::methodName
- :: 是jdk8新添加分隔符,专门用于此处
- 函数式接口的方法要和静态方法兼容,比如下面的func 方法和strReverse兼容
代码示例
函数式接口
interface StringFunc{String func(String str);
}
静态方法
public static String StrReverse(String str){char[] chars = new char[str.length()];for(int i=0;i<str.length();i++){chars[i] = str.charAt(str.length()-1-i);}return new String(chars);}
方法引用
public static String stringOpts(StringFunc func,String str){return func.func(str);}
测试方法
public static void main(String[] args) {String result = stringOpts(MyStringOpts::StrReverse,"helllo lambda static");System.out.println(result);}
//输出
//citats adbmal ollleh
实例中使用
对象调用
objRef::methodname
需要先 new 对象在进行调用
interface StringFunc{String func(String str);
}
class ObjRef{public String reverse(String str){StringBuffer buf = new StringBuffer();for(int i=0;i<str.length();i++){buf.append(str.charAt(str.length()-1-i));}return buf.toString();}}
class MainTest1{public static String stringOpts(StringFunc func,String str){return func.func(str);}public static void main(String[] args) {ObjRef objRef = new ObjRef();String result = stringOpts(objRef::reverse,"你好 lambda");System.out.println(result);}
}
//输出
//adbmal 好你
实例方法
className::methodName
- 第一个参数匹配调用对象
- 第二个参数匹配调用方法的参数
具体请看代码示例:
函数式接口
注意这个函数有两个参数
interface MyFunc<T>{boolean func(T t1,T t2);
}
实体对象
主要使用下面的equals,lessThan方法,两个方法中的参数对应函数式接口中的第二个参数
class Student{private Integer glades;public Student(Integer glades){this.glades = glades;}public boolean equals(Student student){return glades == student.glades;}public boolean lessThan(Student student){return glades < student.glades;}}
方法引用
public static <T> int count(T[] val,MyFunc<T> f,T v){int count = 0;for(int i=0;i<val.length;i++){if(f.func(val[i],v))count++;}return count;}
测试
Student[] arrs = new Student[]{new Student(50),new Student(60),new Student(60),new Student(80),new Student(90)};int ret = count(arrs,Student::equals,new Student(60));System.out.println(ret);
//2int ret1 = count(arrs,Student::lessThan,new Student(60));System.out.println(ret1);
//2
泛型中引用
接口
interface MyFunc<T>{int func(T[] vals,T t);
}
泛型方法,非泛型类
public class FanxingLambda {static <T> int countMath(T[] vals,T t){int count = 0;for(int i=0;i<vals.length;i++){if(vals[i] == t)count++;}return count;}
}
引用方法
public static <T> int countFun(MyFunc<T> f,T[] vals,T t){return f.func(vals,t);}
测试方法
public static void main(String[] args) {Integer[] arrs = new Integer[]{1,2,3,4,5,2,4,5,2,1,2,3};int count = countFun(FanxingLambda::<Integer>countMath,arrs,2);System.out.println(count);}
注意
int count = countFun(FanxingLambda::<Integer>countMath,arrs,2);
FanxingLambda::countMath
因为FanxingLambda不是泛型类,但是countMath是泛型方法,所以可以在::前面指定Integer类型
也可以不写,因为类型参数会推断出类型
找出最大值示例
需要使用Collections.max方法,其中第二个参数传入一个比较器Comparator
源码
Collections : public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)
Comparator: int compare(T o1, T o2);
测试代码
实体
class Salary{private double val;public Salary(double val){this.val = val;}public double getVal(){return val;}public static int comparaSalary(Salary s1,Salary s2){return (int)(s1.val - s2.val);}
}
测试方法
public static void main(String[] args) {List<Salary> list = new ArrayList<>();list.add(new Salary(100.1));list.add(new Salary(2000.3));list.add(new Salary(1000));list.add(new Salary(3000.5));list.add(new Salary(235));Salary s = Collections.max(list,Salary::comparaSalary);System.out.println(s.getVal());}//3000.5
构造函数引用
classname::new
interface ClassFun<T,V>{T func(V v);
}
class Emp{private Integer age;public Emp(Integer age){this.age = age;}public Integer getAge(){return age;}
}
class People<T>{private T t;public People(T t){this.t = t;}public T getVal(){return t;}
}
ClassFun<Emp,Integer> c = Emp::new;Emp e = c.func(100);System.out.println(e.getAge());ClassFun<People<String>,String> c1 = People::new;People<String> p = c1.func("zhangsan");System.out.println(p.getVal());//100//zhangsan