lambda概念
jdk 1.8以后引入了lambda这一特性,其概念如下:
1、lamdba表达式也被称为箭头函数,匿名内部类,闭包。
2、体现的是轻量级的函数式编程思想。
3、’->’ 符号为核心符号即操作符号,左侧是所需要的传入的参数,右边是具体操作的数据。
lambda处理那些问题
1、实现了编码即数据(Model Codl as Data)尽量的将代码轻量封装起来。
2、处理了语法冗余,this关键字,变量捕获,数据控制不友好等问题,
3、lambda表达式不是新的技术,是对现有技术的语义优化方案,需要考虑实际的性能问题。
传统编码和lamdba的区别实例一:
public static void main(String[] args) {
// 传统代码
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("传统模式下的多线程创建" +
Thread.currentThread().getName());
}
}).start();
// 使用lambda 表达式
new Thread(() -> {
System.out.println("lambda--->thread" + Thread.currentThread().getName());
}).start();
}
函数式接口(function interface)
函数式接口。是指只包含一个操作方法,lambda表达式,也只能操作一个方法。java中lambda核心就是一个函数式接口打实现。
就是java系统中打接口,只包含一个接口方法的特殊接口。如
// @Functionallnterface 语义检查是否符合lambda语义规范
@FunctionalInterface
public interface CommonUtil {
// 是否为空
boolean isEmpty(String str);
}
除了抽象方法还可以包含静态方法及默认方法
@FunctionalInterface
public interface FunctionalInterfaceImpl {
/**
* 抽象方法
*
* @param arr
* @return
*/
String convertArr(String[] arr);
/**
* 默认方法
*
* @return Arr
* @Param s
*/
default String stringToArr(String s) {
return null;
}
/**
* 静态方法
* @param s
* @return
*/
static boolean isEmpty(String s) {
// 具体逻辑
return false;
}
}
除了抽象接口和默认方法及静态方法。由于函数式接口是java类型系统中的接口,所以间接的也就继承了Object类,所以实现Object的方法也是可以通过语义检查的。
@FunctionalInterface
public interface CommonUtil {
// 是否为空
boolean isEmpty(String str);
// Object的方法
int hashCode();
boolean equals(Object obj);
String toString();
}
java类型系统内见函数式接口
java 8以上在java.util.function提供了常用打函数式接口
以下都是提供函数是接口打功能
java.lang.Runable
java.lang.Comparabale
java.lang.Comparator
java.io.FileFilter
java.util.function.Predicate 接受参数T返回一个boolean值
Predicate源码
@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);
}
}
具体使用如:
Predicate<String > res = (String str) -> {
return str.equals("");
};
System.out.println(res.test("fb"));
System.out.println(res.test(""));
java.util.function.Comsumer 接受参数T,不返回任何值
Comsumer源码
package java.util.function;
import java.util.Objects;
@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); };
}
}
使用实例如:
Consumer<String> consumer = (String str) ->{
System.out.println("传过来的参数为:" + str);
};
consumer.accept("paraemter");
java.util.function.Function<T,R> 接受一个T参数返回一个R结果
源码如下
/*
package java.util.function;
import java.util.Objects;
@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;
}
}
使用实例:
Function<Integer,String> function = (Integer para) -> {
return para instanceof Integer ? "int" : "string";
};
System.out.println(function.apply(3));
System.out.println(function.apply(9));
java.util.function.Supplier 不接收参数,提供对T类型的创建工厂
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
java.util.function.UnaryOperator
接收参数T,返回一个T
java.util.function.BiFunction<T,U,R>接收两个参数T和U,返回一个R 结果
@FunctionalInterface
public interface BiFunction<T, U, R>
R apply(T t, U u);
java.util.function.BinaryOperator 继承了BiFunction<T,T,T>
接收两个参数T,返回一个T
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
}
java.utili.function.BiPredicate<T, U>接收两个参数类型返回一个boolean结果
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
Objects.requireNonNull(other);
return (T t, U u) -> test(t, u) && other.test(t, u);
}
default BiPredicate<T, U> negate() {
return (T t, U u) -> !test(t, u);
}
default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
Objects.requireNonNull(other);
return (T t, U u) -> test(t, u) || other.test(t, u);
}
}
lambda基本使用
1 声明:就是和lambda表达式绑定接口类型
2 参数:在操作符号’->’ 左侧,在一个园括号中,和绑定打接口中的抽象方法的参数个数及顺序是一致。
3 操作符: lambda核心操作符 ‘->’
4 执行代码块:在操作符的右侧,包含一对大括号中。
语法如 :[接口声明] = (参数)-> {执行代码块}
变量访问操作
1 匿名内部类
全局变量和局部变量和内部变量
全局变量 直接直接访问,局部变量也是可以的,但是局部变量不能修改,默认推导修饰符使用的
this关键字表示的是当前内部类,对当前内部类的访问可以使用this.内部变量,但是不能修改。
2 lambda表达式
this关键字,表示的就是所属方法在所在类型的对象。既可以访问也可以修改。
同样局部变量也可直接访问但是不能修改。
内部变量可以直接修改。
public class ThisMain {
// 全局变量
String str1 = "全局变量";
public void innerClass() {
// 局部变量
String str2 = "局部变量";
new Thread(new Runnable() {
// 内部变量
String str3 = "内部变量";
@Override
public void run() {
System.out.println(str1); // this表示当前内部类型的对象
str3 = "f";
System.out.println(str2); // 可以访问,但是不可以修改
System.out.println(this.str3);
System.out.println(str3);
}
}).start();
}
public void lambdaThis() {
String str2 = "局部变量";
new Thread( () -> {
String str3 = "内部类型的变量";
System.out.println(this.str1); // 此时的this 关键字为 所属的方法所在类型的对象
System.out.println(str1);
System.out.println(str2); // 不能修改,默认的类型推导的修饰符为final
System.out.println(str3);
}).start();
}
public static void main(String[] args) {
ThisMain main = new ThisMain();
main.innerClass();
main.lambdaThis();
}
}
lambda表达式类型检查
类型检查包括:
- 表达式的类型检查
- 参数类型检查
如下实例:
public class MainDemo {
public static void test(ListUtils<String, List> para) {
List<String> res = para.add("参数", new ArrayList<>());
System.out.println(res);
}
public static void main(String[] args) {
test(new ListUtils<String, List>() {
@Override
public List add(String s, List list) {
list.add(s);
return list;
}
});
// 使用lambda表达
test((x, y) -> {
y.add(x);
return y;
});
}
}
@FunctionalInterface
interface ListUtils<R, T> {
T add(R r, T t);
}
lambda表达式对方法重构表达式的影响
通过一段代码观察lambda对方法重构的影响
public class App {
interface Param1{
void method(String param);
}
interface Param2{
void method(String param);
}
public void lambdaMethod(Param1 param) {
param.method("重构方法一");
}
public void lambdaMethod(Param2 param) {
param.method("重构方法二");
}
public static void main(String[] args) {
App app = new App();
// 匿名内部类一(Param1)
app.lambdaMethod(new Param1() {
@Override
public void method(String param) {
System.out.println(param);
}
});
// 匿名内部类二(Param2)
app.lambdaMethod(new Param2() {
@Override
public void method(String param) {
System.out.println(param);
}
});
/**
* lambda表达式在类型检查会自动推导目标类型
* lambdaMethod() -> 方法 -> 重构方法
* -> Param1 函数式 接口
* -> Param2 函数式接口
* 调用方法 -> 传递lambda表达式 -> jvm自动类型推导 -> Param1 或 Param2
* 然后出现混淆的
*/
// 编译不通过
app.lambdaMethod(() -> System.out.println());
}
}
对于重构方法lambda在类型检查自动推导目标类型 ,然后对于重构方法容易导致目标类型出现混淆的问题,所以存在重构方法是尽量使用匿名内部类。