JDK1.8 関数型プログラミング Lambda
1。概要
- 関数型プログラミングの概念は JDK 1.8 で提案されましたが、コードを記述する最も破壊的な方法は間違いなく Lambda です。
Lambda 式を使用するための要件も比較的単純です。1 . 関数の実装には最初にインターフェイスが
必要です。2. 次に、インターフェイスには抽象メソッドが 1 つだけあります。Lambdaは匿名内部クラス モードに似ています。インターフェイス内の抽象メソッドは関数実装は匿名内部クラスの実装に似ているため、インターフェイス内で複数の抽象メソッドを許可しません。そうでない場合は、どのメソッドが実装されているかを判断できません。
例:
ここでは、Runable インターフェイスの run() メソッドを実装するために Lambda が使用されています。
public class View01 {
public static void main(String[] args) {
new Thread( () -> {
System.out.println("体验 lambdaλ");
}).start();
}
}
2. はじめに
- Lambda の標準的な使用形式は次のとおりです。
() -> {}
括弧内はパラメータの配置位置、中括弧内はメソッド本体の記述位置で
、実装が簡単なメソッドです。
- 使用例:
/**
* 抽象方法无参无返回值
*/
public interface Interface1 {
void method();
}
/**
* 抽象方法带参无返回值
*/
public interface Interface2 {
void method(String str);
}
/**
* 抽象方法带参带返回值
*/
public interface Interface3 {
String method(String name, int age);
}
/**
* Lambda
*/
public class Lambda_Pratice_Test1 {
public static void main(String[] args) {
// Lambda表达式练习(抽象方法无参无返回值)
test1(() -> {
System.out.println("test1");
});
// Lambda表达式练习(抽象方法带参无返回值)
test2((String s) -> {
System.out.println(s);
}, "test2");
// Lambda表达式练习(抽象方法带参带返回值)
String result = test3((String name, int age) -> {
return name + age;
}, "chenfeilin ", 24);
System.out.println(result);
}
private static void test1(Interface1 interface1) {
interface1.method();
}
private static void test2(Interface2 interface2, String str) {
interface2.method(str);
}
private static String test3(Interface3 interface3, String name, int age) {
String result = interface3.method(name, age);
return result;
}
}
3. パターンと注意事項を省略する
/**
* Lambda表达式的省略模式
* Lambda表达式的注意事项
*/
public class Lambda_Pratice_Test2 {
public static void main(String[] args) {
// Lambda表达式的省略模式
/**
* 可推导的就是可省略的
* 参数类型可以省略,如果参数只有一个,圆括号可省略
* 如果方法体只有一句,花括号,结尾分号可省略,return关键字也可以省略,如果有的话
*/
test2(s -> System.out.println(s), "test2");
test3((name, age) -> name + age, "test3", 24);
// Lambda表达式的注意事项
/**
* lambda的使用需要依赖上下文环境,也就是不能随便写
* 最常用的就是作为参数或者返回值
* 以及作为局部变量赋值
*/
// 直接这么写是不行的
// () -> {System.out.println("this is interface1 method");}
Interface1 interface1 = () -> {
System.out.println("this is interface1 method");
};
interface1.method();
}
private static void test2(Interface2 interface2, String str) {
interface2.method(str);
}
private static String test3(Interface3 interface3, String name, int age) {
String result = interface3.method(name, age);
return result;
}
}
4.ラムダ式と匿名内部クラスの違い
/**
* Lambda 和 匿名内部类的区别
*/
public class Lambda_Test {
public static void main(String[] args) {
// 区别1:使用类型场景的不同
// 匿名内部类:接口,抽象类,具体类都可以
// useInterface(new Itface() {
// @Override
// public void method() {
// System.out.println("useInterface");
// }
// });
//
// useAbstract(new AbstractClass() {
// @Override
// public void method() {
// System.out.println("useAbstract");
// }
// });
//
// useTrueClass(new TrueClass() {
// @Override
// public void method() {
// System.out.println("useTrueClass");
// }
// });
// lambda:只有接口可以,抽象类和具体类不行
// useInterface(() -> System.out.println("useInterface"));
// Target type of a lambda conversion must be an interface
// useAbstract(() -> System.out.println("aaa"));
// useTrueClass(() -> System.out.println("aaa"));
// ------------------------------------------------------------------------------
// 区别2:使用局限性不同
// 在接口中有多个抽象方法时,是无法使用lambda的,但是匿名内部类可以
useInterface(new Itface() {
@Override
public void method() {
System.out.println("m1");
}
@Override
public void method2() {
System.out.println("m2");
}
});
// 区别3:在具体的代码实现上
// 匿名内部类会生成一个单独class文件
// 而lambda不会,他的匿名类文件是动态生成的
}
public static void useInterface(Itface itface){
itface.method();
}
public static void useAbstract(AbstractClass abstractClass) {
abstractClass.method();
}
public static void useTrueClass(TrueClass trueClass) {
trueClass.method();
}
}
public abstract class AbstractClass {
public abstract void method();
}
public interface Itface {
public void method();
public void method2();
}
public class TrueClass {
public void method(){
}
}
5.メソッドの引用::
Lambda 式を使用する場合、実際に渡すコードは解決策です。パラメーターを操作するには、
状況を考慮してください。Lambda で指定する操作プランがすでに同じプランである場合、繰り返しロジックを記述する必要がありますか?
答えは必ずしも必要ではありませんが、
既存のソリューションをどのように使用すればよいでしょうか?
これはこれから説明するメソッド リファレンスであり、メソッド リファレンスを通じて既存のソリューションを使用します。
メソッド参照記号は 2 つのコロンで構成されます。通常、左側はクラス名またはオブジェクト インスタンス、右側は通常、メソッド名です。パラメーターは記述されないことに注意してください。例:
Student
::study
コード例:
public interface PrintAble {
void print(String s);
}
public class Test_method {
public static void main(String[] args) {
// 完整版写法
method((String s) -> {
System.out.println("77777777777");
});
// 省略后写法
method(s -> System.out.println("77777777777"));
// 方法引用
method(System.out::println);
}
public static void method(PrintAble printAble) {
printAble.print("sss");
}
}
- 参照クラスメソッド(静的メソッド)
public interface StringToInt {
public int to(String s);
}
public class Method_test {
public static void main(String[] args) {
// 就是普通的静态方法调用
ttt(Integer::parseInt);
}
public static void ttt(StringToInt sti) {
int to = sti.to("666");
System.out.println(to);
}
}
- 参照オブジェクトのインスタンスメソッド
public interface MakeStringUp {
public String upString(String small);
}
public class Stringhelper {
public String Up(String s) {
System.out.println("快快变大!");
return s.toUpperCase();
}
}
public class Test_class {
public static void main(String[] args) {
Stringhelper sh = new Stringhelper();
StringToUp(sh::Up);
}
private static void StringToUp(MakeStringUp msu) {
String hello_small = msu.upString("hello small");
System.out.println(hello_small);
}
}
- 参照クラスのインスタンスメソッド
public class MethodClass {
private String name;
private int age;
public MethodClass() {
}
public MethodClass(String name, int age) {
this.name = name;
this.age = age;
}
public void setField(String str) {
String name = str.split(",")[0];
int age = Integer.parseInt(str.split(",")[1]);
this.name = name;
this.age = age;
System.out.println(name);
System.out.println(age);
}
public static void staticMethod(String str) {
System.out.println(str);
}
public void normalMethod(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "MethodClass{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public interface GetMethodClass {
MethodClass getMethodClass(String name, int age);
}
public class FFYY_Test1 {
public static void main(String[] args) {
// 引用类的实例方法
// 这个类的实例方法名字就很抽象,使用类名,去引用普通方法,一般我们是使用类的实例才能去调用其普通成员方法的。
/**
* 此时
* 接口方法的参数为: (MethodClass methodClass, String str)
* 我们想要引用的方法的参数为: setField(String str)
* 我们想要引用的类的实例为 MethodClass
*
* 这里虽然参数匹配不上 (MethodClass methodClass, String str) != (String str)
* 但是这里是可以使用的,并且调用的时候为 类名::普通方法名
* 这里是没有使用类的实例来做方法调用的,而这个普通方法又必须要类的实例才能调用,因为不是静态方法
* 什么时候可以这么写呢,在接口的参数中包含了这个类的实例的时候,这么写默认就是这个方法参数类实例调用了这个普通方法
* 这里this的赋值也是成功了的
*/
System.out.println("-----------------");
MethodClass m = new MethodClass();
System.out.println(m);
test5(MethodClass::setField, m);
System.out.println(m);
}
private static void test5(InterfaceTest interfaceTest, MethodClass methodClass) {
interfaceTest.interfaceMethod(methodClass , "cfl,24");
}
}
- 参照コンストラクター
public interface StudentBuilder {
Student getSb(String name, int age);
}
public class Student {
private String name = "";
private int age = 0;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
/**
* 方法引用之引用构造方法
* 其实也是引用普通类的方法,不过是构造方法,用了new关键字而已,大可以理解为引用了一个带参数和返回值的普通方法
*/
public class ConstructTest {
public static void main(String[] args) {
// 方法引用
getStudent(Student::new);
}
private static void getStudent(StudentBuilder studentBuilder) {
System.out.println(studentBuilder.getSb("陈菲林", 777));
}
}