Java Lambda 表达式。
文章目录
~
what。
- Lambda 表达式也被称为箭头函数、匿名函数、闭包。
- Lambda 表达式体现的是轻量级函数式编程思想。
->
符号式 Lambda 表达式核心操作符号, 符号左侧是操作参数,符号右侧是操作表达式。- jdk8 新特性。
Model Code As Data。
- Model Code as Data,编码及数据,尽可能轻量级的将代码封装为数据。
- 解决方案:接口 & 实现类(匿名内部类)。
- 令存在问题:语法冗余、this 关键字、变量捕获、数据控制等。
需求。
线程类的创建。
解决方案:匿名内部类实现。+ Lambda 表达式。
package com.geek.lambda;
/**
* @author geek
*/
public class Demo00 {
public static void main(String[] args) {
// 传统模式下新线程的创建。
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("threading..." + Thread.currentThread().getName());
}
}).start();
// Lambda。
new Thread(() -> System.out.println("threading..." + Thread.currentThread().getName())).start();
}
}
为什么要使用 Lambda 表达式。
- 它不是解决未知问题的新技术。
- 对现有解决方案的语义化优化。
- 需要根据实际需求考虑性能问题。
函数式接口。
- 函数式接口,就是 Java 类型系统中的接口。
- 函数式接口,是只包含一个接口方法的特殊接口。
- 语义化检测注解:@Functionallnterface。
package com.geek;
/**
* 用户身份认证标记接口。
*
* @author geek
*/
@FunctionalInterface
public interface IUserCredential {
/**
* 通过用户账号,验证用户身份信息。
*
* @param username 要验证的用户账号。
* @return 身份信息[系统管理员,用户管理员、普通用户。]
*/
String verifyUser(String username);
// boolean test();
// Multiple non-overriding abstract methods found in interface com.geek.IUserCredential
static String getCredential(String username) {
if ("admin".equals(username)) {
return "admin ~ 系统管理员";
} else if ("manager".equals(username)) {
return "manager ~ 用户管理员";
} else {
return "commons ~ 普通会员用户";
}
}
}
package com.geek;
/**
* 消息传输格式化接口。
*
* @author geek
*/
@FunctionalInterface
public interface IMessageFormat {
/**
* 消息合法性验证。
*
* @param msg 要验证的消息。
* @return 结果。
*/
static boolean verifyMessage(String msg) {
return msg != null;
}
/**
* 消息转换方法。
*
* @param message 要转换的消息。
* @param format 转换的格式[xml/json...]
* @return 返回转换后的数据。
*/
String format(String message, String format);
// 自己定义的方法。
// void test();
// Multiple non-overriding abstract methods found in interface com.geek.IMessageFormat
// 如果是 Object 的方法,编译通过。
String toString();
}
默认接口方法。
package com.geek;
/**
* 用户身份认证标记接口。
*
* @author geek
*/
@FunctionalInterface
public interface IUserCredential {
/**
* 通过用户账号,验证用户身份信息。
*
* @param username 要验证的用户账号。
* @return 身份信息[系统管理员,用户管理员、普通用户。]
*/
String verifyUser(String username);
// boolean test();
// Multiple non-overriding abstract methods found in interface com.geek.IUserCredential
static String getCredential(String username) {
if ("admin".equals(username)) {
return "admin ~ 系统管理员";
} else if ("manager".equals(username)) {
return "manager ~ 用户管理员";
} else {
return "commons ~ 普通会员用户";
}
}
}
package com.geek;
import com.geek.impl.MessageFormatImpl;
import com.geek.impl.UserCredentialImpl;
/**
* Hello World!
*
* @author geek
*/
public class App1 {
public static void main(String[] args) {
// System.out.println( "Hello World!" );
IUserCredential userCredential = new UserCredentialImpl();
System.out.println(userCredential.verifyUser("admin"));
// 系统管理员
/**
* 需求改动:
* 所有的用户验证。可以同时获取用户的验证信息[是否验证成功 | 成功 ~ 返回用户 | null]
*
* jdk 1.8 以前只能修改实现类。
*/
System.out.println(IUserCredential.getCredential("admin"));
// admin ~ 系统管理员
}
}
静态接口方法。
package com.geek;
/**
* 消息传输格式化接口。
*
* @author geek
*/
@FunctionalInterface
public interface IMessageFormat {
/**
* 消息合法性验证。
*
* @param msg 要验证的消息。
* @return 结果。
*/
static boolean verifyMessage(String msg) {
return msg != null;
}
/**
* 消息转换方法。
*
* @param message 要转换的消息。
* @param format 转换的格式[xml/json...]
* @return 返回转换后的数据。
*/
String format(String message, String format);
// 自己定义的方法。
// void test();
// Multiple non-overriding abstract methods found in interface com.geek.IMessageFormat
// 如果是 Object 的方法,编译通过。
String toString();
}
- 实现类。
package com.geek.impl;
import com.geek.IMessageFormat;
/**
* @author geek
*/
public class MessageFormatImpl implements IMessageFormat {
@Override
public String format(String message, String format) {
System.out.println("消息转换。");
return message;
}
}
package com.geek;
import com.geek.impl.MessageFormatImpl;
import com.geek.impl.UserCredentialImpl;
/**
* Hello World!
*
* @author geek
*/
public class App1 {
public static void main(String[] args) {
String msg = "hello world";
if (IMessageFormat.verifyMessage(msg)) {
IMessageFormat format = new MessageFormatImpl();
System.out.println(format.format(msg, "json"));
}
}
}
继承自 Object 的方法。
package com.geek;
/**
* 消息传输格式化接口。
*
* @author geek
*/
@FunctionalInterface
public interface IMessageFormat {
/**
* 消息合法性验证。
*
* @param msg 要验证的消息。
* @return 结果。
*/
static boolean verifyMessage(String msg) {
return msg != null;
}
/**
* 消息转换方法。
*
* @param message 要转换的消息。
* @param format 转换的格式[xml/json...]
* @return 返回转换后的数据。
*/
String format(String message, String format);
// 自己定义的方法。
// void test();
// Multiple non-overriding abstract methods found in interface com.geek.IMessageFormat
// 如果是 Object 的方法,编译通过。
@Override
String toString();
}
Lambda 表达式和函数式接口的关系。
-
函数式接口,只包含一个操作方法。
-
Lambda 表达式,只能操作一个方法。
-
Java 中的 Lambda 表达式,核心就是一个函数式接口的实现。
匿名内部类。
package com.geek;
import com.geek.impl.MessageFormatImpl;
import com.geek.impl.UserCredentialImpl;
/**
* Hello World!
*
* @author geek
*/
public class App1 {
public static void main(String[] args) {
// 匿名内部类实现接口的抽象方法。
IUserCredential ic2 = new IUserCredential() {
@Override
public String verifyUser(String username) {
return "admin".equals(username) ? "管理员" : "会员";
}
};
System.out.println(ic2.verifyUser("manager"));
System.out.println(ic2.verifyUser("admin"));
}
}
package com.geek;
import com.geek.impl.MessageFormatImpl;
import com.geek.impl.UserCredentialImpl;
/**
* Hello World!
*
* @author geek
*/
public class App1 {
public static void main(String[] args) {
// Lambda 表达式。针对函数式接口的简单实现。
IUserCredential ic3 = (String username) -> "admin".equals(username) ? "lbd 管理员" : "lbd 会员";
System.out.println(ic3.verifyUser("manager"));
System.out.println(ic3.verifyUser("admin"));
}
}
jdk 中常见的函数式接口。
java 类型系统内建函数式接口。
- java.lang.Runnable。
- java.lang.Comparable。
- java.lang.Comparator。
- java.io.FileFilter。
jdk 8 提供了 java.util.function 包,提供了常用的函数式功能接口。
@FunctionalInterface
public interface Predicate<T> {
// 接受参数对象 T,返回一个 boolean 类型结果。
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util.function;
import java.util.Objects;
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
/**
* Returns a composed predicate that represents a short-circuiting logical
* AND of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* Returns a composed predicate that represents a short-circuiting logical
* OR of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**
* Returns a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
package com.geek;
import java.util.UUID;
import java.util.function.*;
/**
* @author geek
*/
public class App2 {
public static void main(String[] args) {
Predicate<String> predicate = (String username) -> "admin".equals(username);
// Predicate<String> predicate = "admin"::equals;
// 接受参数对象 T,返回一个 boolean 类型结果。
System.out.println(predicate.test("manager"));
System.out.println(predicate.test("admin"));
}
}
@FunctionalInterface
public interface Consumer<T> {
// 接受参数对象 T,不反回结果。
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util.function;
import java.util.Objects;
/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
package com.geek;
import java.util.UUID;
import java.util.function.*;
/**
* @author geek
*/
public class App2 {
public static void main(String[] args) {
Consumer<String> consumer = (String msg) -> {
System.out.println("要发送的消息:" + msg);
System.out.println("消息发送完成。");
};
// 接受参数对象 T,不反回结果。
consumer.accept("Hello");
consumer.accept("Hello1");
}
@FunctionalInterface
public interface Function<T, R> {
// 接受参数对象 T,返回结果对象 R。
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util.function;
import java.util.Objects;
/**
* Represents a function that accepts one argument and produces a result.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object)}.
*
* @param <T> the type of the input to the function
* @param <R> the type of the result of the function
*
* @since 1.8
*/
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies this function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the
* composed function
* @param before the function to apply before this function is applied
* @return a composed function that first applies the {@code before}
* function and then applies this function
* @throws NullPointerException if before is null
*
* @see #andThen(Function)
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*
* @see #compose(Function)
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* Returns a function that always returns its input argument.
*
* @param <T> the type of the input and output objects to the function
* @return a function that always returns its input argument
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
package com.geek;
import java.util.UUID;
import java.util.function.*;
/**
* @author geek
*/
public class App2 {
public static void main(String[] args) {
Function<String, Integer> fun = (String gender) -> "male".equals(gender) ? 1 : 0;
// 接受参数对象 T,返回结果对象 R。
System.out.println(fun.apply("male"));
System.out.println(fun.apply("female"));
}
}
@FunctionalInterface
public interface Supplier<T> {
// // 不接受参数,提供 T 对象的创建工厂。
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util.function;
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
package com.geek;
import java.util.UUID;
import java.util.function.*;
/**
* @author geek
*/
public class App2 {
public static void main(String[] args) {
Supplier<String> supplier = () -> UUID.randomUUID().toString();
// 不接受参数,提供 T 对象的创建工厂。
System.out.println(supplier.get());
System.out.println(supplier.get());
System.out.println(supplier.get());
}
}
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
// 接受参数对象 T,返回结果对象。
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util.function;
/**
* Represents an operation on a single operand that produces a result of the
* same type as its operand. This is a specialization of {@code Function} for
* the case where the operand and result are of the same type.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object)}.
*
* @param <T> the type of the operand and result of the operator
*
* @see Function
* @since 1.8
*/
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
*
* @param <T> the type of the input and output of the operator
* @return a unary operator that always returns its input argument
*/
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
package com.geek;
import java.util.UUID;
import java.util.function.*;
/**
* @author geek
*/
public class App2 {
public static void main(String[] args) {
UnaryOperator<String> unaryOperator = (String img) -> {
img += "[100x200]";
return img;
};
// 接受参数对象 T,返回结果对象。
System.out.println(unaryOperator.apply("原图---"));
// 原图---[100x200]
}
}
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
// 接受两个 T 对象,返回一个 T 对象结果。
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util.function;
import java.util.Objects;
import java.util.Comparator;
/**
* Represents an operation upon two operands of the same type, producing a result
* of the same type as the operands. This is a specialization of
* {@link BiFunction} for the case where the operands and the result are all of
* the same type.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object, Object)}.
*
* @param <T> the type of the operands and result of the operator
*
* @see BiFunction
* @see UnaryOperator
* @since 1.8
*/
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
/**
* Returns a {@link BinaryOperator} which returns the lesser of two elements
* according to the specified {@code Comparator}.
*
* @param <T> the type of the input arguments of the comparator
* @param comparator a {@code Comparator} for comparing the two values
* @return a {@code BinaryOperator} which returns the lesser of its operands,
* according to the supplied {@code Comparator}
* @throws NullPointerException if the argument is null
*/
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
/**
* Returns a {@link BinaryOperator} which returns the greater of two elements
* according to the specified {@code Comparator}.
*
* @param <T> the type of the input arguments of the comparator
* @param comparator a {@code Comparator} for comparing the two values
* @return a {@code BinaryOperator} which returns the greater of its operands,
* according to the supplied {@code Comparator}
* @throws NullPointerException if the argument is null
*/
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
}
package com.geek;
import java.util.UUID;
import java.util.function.*;
/**
* @author geek
*/
public class App2 {
public static void main(String[] args) {
BinaryOperator<Integer> binaryOperator = (Integer i1, Integer i2) -> i1 > i2 ? i1 : i2;
// 接受两个 T 对象,返回一个 T 对象结果。
System.out.println(binaryOperator.apply(12, 13));
}
}
Lambda 表达式语法。
必须和接口绑定。
Lambda 表达式基本语法。
package com.geek;
/**
* @author geek
*/
public class LambdaApp {
/*
基本语法。
- 声明:Lambda 表达式绑定的接口类型。
- 参数:包含在一对圆括号中,和绑定的接口中的抽象方法的参数个数及顺序一致。
- 操作符:->
- 执行代码块:包含在一堆大括号中,出现在操作符号的右侧。
[接口声明] = (参数) -> {执行代码块};
*/
public static void main(String[] args) {
Ilambda1 i1 = () -> {
System.out.println("hello");
System.out.println("hello1");
};
i1.test();
Ilambda1 i12 = () -> System.out.println("hello");
i12.test();
Ilambda2 i2 = (String s, int a) -> System.out.println(s + " says: my age is " + a);
i2.test("geek", 3);
}
// 没有参数没有返回值的 Lambda 表达式绑定的接口。
interface Ilambda1 {
void test();
}
}
带参数的 Lambda 表达式。
package com.geek;
/**
* @author geek
*/
public class LambdaApp {
/*
基本语法。
- 声明:Lambda 表达式绑定的接口类型。
- 参数:包含在一对圆括号中,和绑定的接口中的抽象方法的参数个数及顺序一致。
- 操作符:->
- 执行代码块:包含在一堆大括号中,出现在操作符号的右侧。
[接口声明] = (参数) -> {执行代码块};
*/
public static void main(String[] args) {
Ilambda2 i2 = (String s, int a) -> System.out.println(s + " says: my age is " + a);
i2.test("geek", 3);
// 可以不写参数类型。
Ilambda2 i21 = (s, a) -> System.out.println(s + " says: my age is " + a);
i21.test("geek", 3);
}
// 有参数没有返回值的 Lambda 表达式绑定的接口。
interface Ilambda2 {
void test(String name, int age);
}
}
带返回值的 Lambda 表达式。
package com.geek;
/**
* @author geek
*/
public class LambdaApp {
/*
基本语法。
- 声明:Lambda 表达式绑定的接口类型。
- 参数:包含在一对圆括号中,和绑定的接口中的抽象方法的参数个数及顺序一致。
- 操作符:->
- 执行代码块:包含在一堆大括号中,出现在操作符号的右侧。
[接口声明] = (参数) -> {执行代码块};
*/
public static void main(String[] args) {
Ilambda3 i3 = (x, y) -> x + y;
System.out.println(i3.test(1, 2));
}
// 有参数和返回值的 Lambda 表达式绑定的接口。
interface Ilambda3 {
int test(int x, int y);
}
}
变量捕获。
匿名内部类中的变量捕获。
package com.geek;
/**
* @author geek
*/
public class App3 {
private String s1 = "全局变量";
public static void main(String[] args) {
App3 app3 = new App3();
app3.testInnerClass();
}
// 匿名内部类中对变量的访问。
private void testInnerClass() {
String s2 = "局部变量";
new Thread(new Runnable() {
String s3 = "内部变量";
@Override
public void run() {
// 访问全局变量。
// System.out.println(this.s1);// this 关键字 ~ 表示当前内部类型的对象。
System.out.println(s1);
// 访问局部变量。
System.out.println(s2);
// s2 = "hello";// 不能对局部变量进行修改(final)。
System.out.println(s3);
System.out.println(this.s3);
}
}).run();
}
}
Lambda 表达式中的变量捕获。
package com.geek;
/**
* @author geek
*/
public class App3 {
private String s1 = "全局变量";
public static void main(String[] args) {
App3 app3 = new App3();
// app3.testInnerClass();
app3.testLambda();
}
// Lambda 表达式变量捕获。
private void testLambda() {
String s2 = "局部变量 Lambda";
new Thread(() -> {
String s3 = "内部变量 Lambda";
// 访问全局变量。
System.out.println(this.s1);// this 关键字 ~ 表示的就是所属方法所在的类型的对象。
// 访问局部变量。
System.out.println(s2);
// s2 = "hello";// 不能对局部变量进行修改(final)。
System.out.println(s3);
s3 = "Lambda 内部变量直接修改。";
}).start();
}
}
Lambda 表达式类型检查。
Lambda 表达式类型检查。
package com.geek;
import java.util.ArrayList;
import java.util.List;
@FunctionalInterface
interface MyInterface<T, R> {
R strategy(T t, R r);
}
/**
* @author geek
*/
public class App4 {
private static void test(MyInterface<String, List> inter) {
List<String> list = inter.strategy("hello", new ArrayList());
System.out.println(list);
}
public static void main(String[] args) {
test(new MyInterface<String, List>() {
@Override
public List strategy(String s, List list) {
list.add(s);
return list;
}
});
test((x, y) -> {
y.add(x);
return y;
});
/*
(x, y) -> { ... } ==> test(param) ==> param == MyInterface ==> Lambda 表达式 ==> MyInterface 类型。
这个就是对于 Lambda 表达式的类型检查。MyInterface 接口就是 Lambda 表达式的目标类型(Target Typing)。
*/
}
}
Lambda 参数类型检查。
package com.geek;
import java.util.ArrayList;
import java.util.List;
@FunctionalInterface
interface MyInterface<T, R> {
R strategy(T t, R r);
}
/**
* @author geek
*/
public class App4 {
private static void test(MyInterface<String, List> inter) {
List<String> list = inter.strategy("hello", new ArrayList());
System.out.println(list);
}
public static void main(String[] args) {
test(new MyInterface<String, List>() {
@Override
public List strategy(String s, List list) {
list.add(s);
return list;
}
});
test((x, y) -> {
y.add(x);
return y;
});
/*
(x, y) -> { ... } ==> test(param) ==> param == MyInterface ==> Lambda 表达式 ==> MyInterface 类型。
这个就是对于 Lambda 表达式的类型检查。MyInterface 接口就是 Lambda 表达式的目标类型(Target Typing)。
(x, y) -> { ... } ==> MyInterface.strategy(T t, R r) ==> MyInterface<String, List> inter
==> T==String R==List ==> lambda (x, y) == strategy(T t, R r) ==> x == T == String, y == R == List
Lambda 表达式参数的类型检查。
*/
test((x, y) -> {
y.add(x);
return y;
// x.add();// Cannot resolve method 'add()'
});
}
}
方法重载和 Lambda 表达式。
Java 类型系统中的方法重载。
方法重载的实现。
当方法重载遇上 Lambda 表达式。
package com.geek;
/**
* @author geek
*/
public class App5 {
public static void main(String[] args) {
App5 app = new App5();
app.lambdaMethod(new Param1() {
@Override
public void outInfo(String info) {
System.out.println(info);
}
});
app.lambdaMethod(new Param2() {
@Override
public void outInfo(String info) {
System.out.println(info);
}
});
/*
Lambda 表达式存在类型检查 ->自动推到 Lambda 表达式的目标类型。
lambdaMethod(); 方法是重载方法。
=> Param1 函数式接口。
=> Param2 函数式接口。
调用方法 => 传递 Lambda 表达式 => 自动推导
=> Param1 | Param2
*/
// Ambiguous method call.
// Both lambdaMethod (Param1) in App5
// and lambdaMethod (Param2) in App5 match
// app.lambdaMethod((String info) -> {
// System.out.println(info);
// });
}
// 重载方法。
public void lambdaMethod(Param1 param) {
param.outInfo("hello, param1.");
}
public void lambdaMethod(Param2 param) {
param.outInfo("hello, param2.");
}
interface Param1 {
void outInfo(String info);
}
interface Param2 {
void outInfo(String info);
}
}
深入理解 Lambda 表达式。
- Lambda 表达式底层解析运行原理。
- Lambda 表达式在 JVM 底层解析成私有静态方法和匿名内部类型。
- 通过实现接口的匿名内部类型中接口方法调用静态实现方法,完成 Lambda 表达式的执行。
geek@ubuntu:~/IdeaProjects/lambda_geek/src/main/java/com/geek$ javac App.java
geek@ubuntu:~/IdeaProjects/lambda_geek/src/main/java/com/geek$ javap -p App.class
Compiled from "App.java"
public class com.geek.App {
public com.geek.App();
public static void main(java.lang.String[]);
private static void lambda$main$0(java.lang.String);
}
C:\Users\geek\Desktop>G:\lyfGeek\ProgramFiles\Java\jdk1.8.0_241\bin\javac App.java
C:\Users\geek\Desktop>G:\lyfGeek\ProgramFiles\Java\jdk1.8.0_241\bin\javap -p App.class
Compiled from "App.java"
public class App {
public App();
public static void main(java.lang.String[]);
private static void lambda$main$0(java.lang.String);
}
C:\Users\geek\Desktop>G:\lyfGeek\ProgramFiles\Java\jdk1.8.0_241\bin\java -Djdk.internal.lambda.dumpProxyClasses App
lambda!
C:\Users\geek\Desktop>G:\lyfGeek\ProgramFiles\Java\jdk1.8.0_241\bin\javap -p App$$Lambda$1.class
final class App$$Lambda$1 implements IMarkUp {
private App$$Lambda$1();
public void markUp(java.lang.String);
}
方法引用。
静态方法引用。
实例方法引用。
构造方法引用。
package com.geek;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
interface IPerson {
/**
* 抽象方法。通过制定类型的构造方法初始化对象数据。
*
* @param name
* @param gender
* @param age
* @return
*/
Person initPerson(String name, String gender, int age);
}
/**
* @author geek
*/
public class Test {
public static void main(String[] args) {
// 静态方法引用。
// 类型名称.方法名称(); ==> 类型名称::方法名称。
List<Person> personList = new ArrayList<>();
personList.add(new Person("Geek1", "男", 25));
personList.add(new Person("Geek2", "男", 18));
personList.add(new Person("Geek3", "男", 3));
personList.add(new Person("Geek4", "男", 21));
personList.add(new Person("Geek5", "男", 9));
// 排序。匿名内部类。
Collections.sort(personList, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
// return 0;
return o1.getAge() - o2.getAge();
}
});
System.out.println(personList);
// 排序。Lambda。
Collections.sort(personList, (p1, p2) -> p1.getAge() - p2.getAge());
System.out.println(personList);
// 排序。静态方法引用。
Collections.sort(personList, Person::compareByAge);
System.out.println(personList);
// ~ ~
// 排序。实例方法引用。
// 创建类型对应的一个对象。 ==> 对象::实例方法名称。
PersonUtil personUtil = new PersonUtil();
Collections.sort(personList, personUtil::compareByName);
System.out.println("Geek1".hashCode());
System.out.println("Geek2".hashCode());
System.out.println(personList);
// 68679309(Geek1)
//68679310(Geek2)
//[Person(name=Geek1, gender=男, age=25), Person(name=Geek2, gender=男, age=18), Person(name=Geek3, gender=男, age=3), Person(name=Geek4, gender=男, age=21), Person(name=Geek5, gender=男, age=9)]
// 构造方法引用。绑定函数式接口。
IPerson iPerson = Person::new;
Person person = iPerson.initPerson("Tom", "男", 23);
System.out.println(person);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private String name;
private String gender;
private int age;
static int compareByAge(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}
class PersonUtil {
// 增加一个实例方法。
int compareByName(Person p1, Person p2) {
return p1.getName().hashCode() - p2.getName().hashCode();
}
}
Stream。
package com.geek;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author geek
*/
public class StreamTest {
public static void main(String[] args) {
// 测试数据:存储多个账号的列表。
List<String> accounts = new ArrayList<>();
accounts.add("tom");
accounts.add("jerry");
accounts.add("beita");
accounts.add("shuke");
accounts.add("geek");
// 长度 >= 5 的有效账号。
for (String account : accounts) {
if (account.length() >= 5) {
System.out.println("有效账号:" + account);
}
}
// 迭代方式。
Iterator<String> iterator = accounts.iterator();
while (iterator.hasNext()) {
String account = iterator.next();
if (account.length() >= 5) {
System.out.println("it 有效账号:" + account);
}
}
// Stream 结合 Lambda 表达式。
List validAccounts = accounts.stream().filter(s -> s.length() >= 5).collect(Collectors.toList());
Stream<String> stream = accounts.stream();
System.out.println(stream);// java.util.stream.ReferencePipeline$Head@2d98a335
System.out.println(validAccounts);
}
}
Stream 集合操作。
package com.geek;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* - 集合操作。
* - Stream 处理流程。
* 数据源。
* 数据转换。
* 获取结果。
* - 获取 Stream 对象。
* - 从集合或数组中获取。
* Collection.stream();。
* Collection.parallelStream();。
* Arrays.stream(T t);。
* - BufferReader。
* BufferReader.lines();。
* - 静态工厂。
* java.util.stream.IntStream.range();。
* java.nio.file.Files.walk();。
* - 自定构建。
* java.util.Spliterator();。
* - more。
* Random.ints();。
* Pattern.splitAsStream();。
* <p>
* - 中间操作 API。(intermediate)。
* 操作结果是一个 Stream。中间操作可以有一或多个连续的中间操作,需要注意的是,中间操作只记录操作方式,不做具体执行,知道结束操作发生时,才做数据的最终执行。
* 中间操作就是业务逻辑处理。
* 中间操作过程:
* 无状态:数据处理时,不受前置操作的影响。
* map / filter / peek / parallel / sequential / unordered。
* 有状态:数据处理时,受到前置操作的影响。
* distinct / sorted / limit / skip。
* <p>
* - 终结操作 / 结束操作。(terminal)。
* 一个 Stream 对象,只能有一个 Terminal 操作。这个操作一旦发生,就会真实处理数据,生成对应的处理结果。
* 终结操作。
* —— 短路操作:当前的 Stream 对象必须处理完集合中所有数据,才能得到处理结果。
* forEach / forEachOrdered / toArray / reduce / collect / min / max / count / iterator。
* —— 非短路操作:当前的 Stream 对象在处理过程中,一旦满足某个条件,就可以得到结果。
* anyMatch / allMatch / noneMatch / findFirst / findAny。
* short-circuiting。无限大的 Stream -> 有限大的 Stream。
*
* @author geek
*/
public class ArraysDemo {
public static void main(String[] args) {
// 批量数据 --> Stream 对象。
// 多个数据。
Stream<String> stream1 = Stream.of("admin", "Tom", "Jerry");
System.out.println("stream1 = " + stream1);
// 数组。
String[] strings = {"geek", "haha"};
Stream<String> stream2 = Arrays.stream(strings);
System.out.println("stream2 = " + stream2);
// 列表。
List<String> list = new ArrayList<>();
list.add("少林");
list.add("武当");
list.add("青城");
list.add("峨眉");
list.add("崆峒");
Stream<String> stream3 = list.stream();
System.out.println("stream3 = " + stream3);
// 集合。
Set<String> set = new HashSet<>();
set.add("少林罗汉拳");
set.add("武当长拳");
set.add("青城剑法");
Stream<String> stream4 = set.stream();
System.out.println("stream4 = " + stream4);
// map。
Map<String, Integer> map = new HashMap<>();
map.put("geek", 3);
map.put("Tom", 12);
map.put("Jerry", 11);
Stream<Map.Entry<String, Integer>> stream5 = map.entrySet().stream();
System.out.println("stream5 = " + stream5);
// Stream 对象对于基本数据类型的功能封装。
// int / long / long。
IntStream.of(10, 20, 30).forEach(System.out::println);
IntStream.range(1, 5).forEach(System.out::println);// 1 ~ 4。
IntStream.rangeClosed(1, 5).forEach(System.out::println);// 1 ~ 5。
// Stream 对象 --> 转换得到指定的数据类型。
// 数组。
// String[] strings1 = stream1.toArray(String[]::new);
// System.out.println("strings1 = " + strings1);
// 字符串。
// String string = stream1.collect(Collectors.joining()).toString();
// System.out.println("string = " + string);
// Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
// string = adminTomJerry
// 列表。
// List<String> list1 = stream1.collect(Collectors.toList());
// System.out.println("list1 = " + list1);
// list1 = [admin, Tom, Jerry]
// 集合。
// Set<String> set1 = stream1.collect(Collectors.toSet());
// System.out.println("set1 = " + set1);
// set1 = [Tom, admin, Jerry]
// map。
Map<String, String> map1 = stream1.collect(Collectors.toMap(x -> x, y -> "value:" + y));
System.out.println("map1 = " + map1);
// map1 = {Tom=value:Tom, admin=value:admin, Jerry=value:Jerry}
}
}
Stream API。
Stream 操作原理。
操作集合元素。
package com.geek;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author geek
*/
public class APIDemo {
public static void main(String[] args) {
List<String> accountList = new ArrayList<>();
accountList.add("Geek");
accountList.add("Tom");
accountList.add("Jerry");
accountList.add("luzhishen");
accountList.add("wusong");
// map(); 中间操作。map(); 方法接收一个 Functional 接口。
// accountList = accountList.stream().map(x -> "梁山好汉:" + x).collect(Collectors.toList());
// accountList.forEach(System.out::println);
System.out.println("~ ~ ~ ~ ~ ~ ~");
// filter(); 添加过滤条件,拂绿符合条件的用户。
// accountList = accountList.stream().filter(x -> x.length() > 5).collect(Collectors.toList());
// accountList.forEach(System.out::println);
// forEach(); 增强型循环。
// accountList.forEach(x -> System.out.println("forEach => " + x));
// 如果要多次迭代操作。
// accountList.forEach(x -> System.out.println("forEach => " + x));
// accountList.forEach(x -> System.out.println("forEach => " + x));
// 冗余。
// ↓ ↓ ↓
// peek(); 中间操作。迭代数据完成数据的依次处理过程。
// accountList.stream()
// .peek(x -> System.out.println("peek 1" + x))
// .peek(x -> System.out.println("peek 2" + x))
// .forEach(System.out::println);
//
// Stream 中对于数字运算的支持。
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(17);
list.add(3);
list.add(11);
list.add(26);
list.add(27);
list.add(27);
// skip(); 中间操作,有状态,跳过部分数据。
// list.stream().skip(3).forEach(System.out::println);
// limit(); 中间操作,有状态,限制输出数据量。
// list.stream().skip(3).limit(2).forEach(System.out::println);
// distinct(); 中间操作,有状态,剔除重复数据。
// list.stream().distinct().forEach(System.out::println);
// sorted(); 中间操作,有状态,排序。
// max(); 获取最大值。
Optional<Integer> optional = list.stream().max((x, y) -> x - y);
System.out.println(optional.get());
// min(); 获取最小值。
// reduce(); 合并处理数据。
Optional<Integer> optional1 = list.stream().reduce((sum, x) -> sum + x);
System.out.println(optional1.get());
}
}