記事ディレクトリ
インターフェースの強化
JDK8 より前のインターフェイスの構造は次のとおりです。
interface 接口名{
静态常量;
抽象方法;
}
JDK8 以降、インターフェイスが追加され、インターフェイスにはデフォルト メソッドと静的メソッドを持つことができます。
interface 接口名{
静态常量;
抽象方法;
默认方法;
静态方法;
}
デフォルトのメソッド
デフォルトのメソッドを追加する理由
JDK8 より前では、インターフェイスには抽象メソッドと静的定数しか含めることができず、次の問題が発生していました。
抽象メソッドがインターフェイスに追加される場合、実装クラスはこの抽象メソッドを実装する必要がありますが、これはインターフェイスの拡張にとって非常に有害です。
interface A{
void test1();
// 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
void test2();
}
class B implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
}
class C implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
}
test3() メソッドをインターフェイス A に追加する場合、インターフェイス B とインターフェイス C の両方を実装する必要がありますが、これはオープンクローズ原則に準拠しません。
デフォルトのメソッド形式
インターフェースのデフォルトメソッドの構文形式は次のとおりです。
interface 接口名{
修饰符 default 返回值类型 方法名{
方法体;
}
}
デフォルトメソッドは実装クラスで実装することも実装しないこともできますが、もちろんインスタンス経由で呼び出すことも可能です。
interface A{
void test1();
// 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
void test2();
/**
* 接口中定义的默认方法
* @return
*/
public default String test3(){
System.out.println("接口中的默认方法执行了...");
return "hello";
}
}
class B implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
@Override
public String test3() {
System.out.println("B 实现类中重写了默认方法...");
return "ok ...";
}
}
class C implements A{
@Override
public void test1() {
}
@Override
public void test2() {
}
}
静的メソッド
静的メソッドの機能は、インターフェイスを拡張することでもあります。
静的メソッドの形式
interface 接口名{
修饰符 static 返回值类型 方法名{
方法体;
}
}
静的メソッドは実装できません。呼び出される場合、インターフェイス タイプ: インターフェイス名.静的メソッド名 () を介してのみ実装できます。
interface A{
void test1();
// 接口中新增抽象方法,所有实现类都需要重写这个方法,不利于接口的扩展
void test2();
/**
* 接口中定义的默认方法
* @return
*/
public default String test3(){
System.out.println("接口中的默认方法执行了...");
return "hello";
}
/**
* 接口中的静态方法
* @return
*/
public static String test4(){
System.out.println("接口中的静态方法....");
return "Hello";
}
}
機能インターフェイス
Lambda 式を使用するための前提条件は、関数型インターフェイスが必要であることです。Lambda 式を使用する場合、インターフェイス名や抽象メソッド名は気にせず、抽象メソッドのパラメーター リストと戻り値の型のみを気にします。したがって、Lambda 式をより便利な方法で使用できるようにするために、JDK は、主に java.util.function パッケージで、一般的に使用される多数の関数インターフェイスを提供します。
サプライヤー
Supplier はパラメータと戻り値を持たないインターフェイスです。ラムダ式の場合は、戻り値のデータ型を指定する必要があります。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
サプライヤー機能インターフェイスの使用
/**
*
*/
public class SupplierTest {
public static void main(String[] args) {
fun1(()->{
int arr[] = {
22,33,55,66,44,99,10};
// 计算出数组中的最大值
Arrays.sort(arr);
return arr[arr.length-1];
});
}
private static void fun1(Supplier<Integer> supplier){
// get() 是一个无参的有返回值的 抽象方法
Integer max = supplier.get();
System.out.println("max = " + max);
}
}
消費者
Consumer はパラメータを持つインターフェイスであり、戻り値はありません。Supplier インターフェイスはデータの生成に使用され、Consumer インターフェイスはデータの消費に使用されます。これを使用する場合は、パラメータの型を定義するジェネリックを指定する必要があります。
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
使用法: 入力データを一律に小文字の出力に変換します。
public class ConsumerTest {
public static void main(String[] args) {
test(msg -> {
System.out.println(msg + "-> 转换为小写:" + msg.toLowerCase());
});
}
public static void test(Consumer<String> consumer){
consumer.accept("Hello World");
}
}
関数
Function はパラメータと戻り値を持つインターフェイスです。Function インターフェイスは、ある種類のデータを基に別の種類のデータを取得します。前者を事前条件、後者を事後条件と呼びます。
@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);
}
使用法: 文字列を渡し、数値を返します。
public class FunctionTest {
public static void main(String[] args) {
test(msg ->{
return Integer.parseInt(msg);
});
}
public static void test(Function<String,Integer> function){
Integer apply = function.apply("666");
System.out.println("apply = " + apply);
}
}
述語
述語はパラメータとブール値の戻り値を持つインターフェイスです。
@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);
}
使用:
public class PredicateTest {
public static void main(String[] args) {
test(msg -> {
return msg.length() > 3;
});
}
private static void test(Predicate<String> predicate){
boolean b = predicate.test("HelloWorld");
System.out.println("b:" + b);
}
}
Predicate のデフォルト メソッドは、論理関係演算、or、negate、および isEquals メソッドを提供します。
package com.bobo.jdk.fun;
import java.util.function.Predicate;
public class PredicateDefaultTest {
public static void main(String[] args) {
test(msg1 -> {
return msg1.contains("H");
},msg2 -> {
return msg2.contains("W");
});
}
private static void test(Predicate<String> p1,Predicate<String> p2){
// p1 包含H 同时 p2 包含W
boolean bb1 = p1.and(p2).test("Hello");
// p1 包含H 或者 p2 包含W
boolean bb2 = p1.or(p2).test("Hello");
// p1 不包含H
boolean bb3 = p1.negate().test("Hello");
System.out.println(bb1); // FALSE
System.out.println(bb2); // TRUE
System.out.println(bb3); // FALSE
}
}
オプションクラス
Java の Optional クラスは、null 安全性の問題を解決するために使用されるツール クラスです。このクラスは Java 8 で導入され、潜在的な null 値を処理するためのよりエレガントで安全な方法を提供します。
以前の null の処理
@Test
public void test01(){
String userName = null;
if(userName != null){
System.out.println("字符串的长度:" + userName.length());
}else{
System.out.println("字符串为空");
}
}
Optionalの基本的な使い方
オプションのオブジェクトの作成方法
/**
* Optional对象的创建方式
*/
@Test
public void test02(){
// 第一种方式 通过of方法 of方法是不支持null的
Optional<String> op1 = Optional.of("zhangsan");
//Optional<Object> op2 = Optional.of(null);
// 第二种方式通过 ofNullable方法 支持null
Optional<String> op3 = Optional.ofNullable("lisi");
Optional<Object> op4 = Optional.ofNullable(null);
// 第三种方式 通过empty方法直接创建一个空的Optional对象
Optional<Object> op5 = Optional.empty();
}
Optionalの一般的なメソッド
/**
* Optional中的常用方法介绍
* get(): 如果Optional有值则返回,否则抛出NoSuchElementException异常
* get()通常和isPresent方法一块使用
* isPresent():判断是否包含值,包含值返回true,不包含值返回false
* orElse(T t):如果调用对象包含值,就返回该值,否则返回t
* orElseGet(Supplier s):如果调用对象包含值,就返回该值,否则返回 Lambda表达式的返回值
* ifPresent
*/
@Test
public void test03(){
Optional<String> op1 = Optional.of("zhangsan");
Optional<String> op2 = Optional.empty();
// 获取Optional中的值
if(op1.isPresent()){
String s1 = op1.get();
System.out.println("用户名称:" +s1);
}
// isPresent()&get()简洁表达
op1.ifPresent(s-> System.out.println("有值:" +s));
if(op2.isPresent()){
System.out.println(op2.get());
}else{
System.out.println("op2是一个空Optional对象");
}
String s3 = op1.orElse("李四");
System.out.println(s3);
String s5 = op2.orElseGet(()->{
return "Hello";
});
System.out.println(s5);
}
メソッドリファレンス
なぜメソッド参照を使用するのでしょうか?
ラムダ式を使用する場合、コードの冗長性も発生する可能性があります。たとえば、ラムダ式を使用して配列の合計を求める場合などです。
public class FunctionRefTest01 {
public static void main(String[] args) {
printMax(a->{
// Lambda表达式中的代码和 getTotal中的代码冗余了
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
});
}
/**
* 求数组中的所有元素的和
* @param a
*/
public void getTotal(int a[]){
int sum = 0;
for (int i : a) {
sum += i;
}
System.out.println("数组之和:" + sum);
}
private static void printMax(Consumer<int[]> consumer){
int[] a= {
10,20,30,40,50,60};
consumer.accept(a);
}
}
上記コードのLambda式で実行するコードはgetTotalメソッドのコードと同じなのでロジックを書き直す必要はなく、この時点で繰り返しコードを「参照」することができます。
public class FunctionRefTest01 {
public static void main(String[] args) {
// :: 方法引用 也是JDK8中的新的语法
printMax(FunctionRefTest02::getTotal);
}
メソッド参照形式
記号表現:::
シンボルの説明: 二重コロンはメソッド参照演算子であり、それが配置されている式は呼び出されます。方法引用
アプリケーション シナリオ: ラムダ式によって実装されるソリューションが他のメソッドに同じソリューションを既に持っている場合は、メソッド参照を使用できます。
メソッド参照に関する注意:
- 参照されるメソッドのパラメータは、インターフェイス内の抽象メソッドのパラメータと同じである必要があります。
- インターフェイス抽象メソッドに戻り値がある場合、参照されるメソッドにも戻り値が必要です。
メソッド参照は JDK8 で非常に柔軟に使用でき、次の形式になります。
- インスタンス名::メソッド名 オブジェクト::メソッド名
- ClassName::staticMethodName クラス名::静的メソッド
- ClassName::methodName クラス名::通常のメソッド
- ClassName::new ClassName::new によって呼び出されるコンストラクター
- TypeName[]::new String[]::new は配列のコンストラクターを呼び出します
オブジェクト名::メソッド名
これが最も一般的な使用法です。メンバー メソッドがクラスにすでに存在する場合は、オブジェクト名を通じてそのメンバー メソッドを参照できます。
public static void main(String[] args) {
Date now = new Date();
Supplier<Long> supplier = ()->{
return now.getTime();};
System.out.println(supplier.get());
// 然后我们通过 方法引用 的方式来处理
Supplier<Long> supplier1 = now::getTime;
System.out.println(supplier1.get());
}
クラス名::静的メソッド名
public class FunctionRefTest04 {
public static void main(String[] args) {
Supplier<Long> supplier1 = ()->{
return System.currentTimeMillis();
};
System.out.println(supplier1.get());
// 通过 方法引用 来实现
Supplier<Long> supplier2 = System::currentTimeMillis;
System.out.println(supplier2.get());
}
}
クラス名::参照インスタンスメソッド
オブジェクト指向 Java では、クラス名は静的メソッドのみを呼び出すことができます。クラス名がインスタンス メソッドを参照するには前提条件があります。実際、最初のパラメータはメソッドの呼び出し元として使用されます。
public class FunctionRefTest05 {
public static void main(String[] args) {
Function<String,Integer> function = (s)->{
return s.length();
};
System.out.println(function.apply("hello"));
// 通过方法引用来实现
Function<String,Integer> function1 = String::length;
System.out.println(function1.apply("hahahaha"));
}
}
クラス名::コンストラクター
コンストラクターの名前はクラス名とまったく同じであるため、コンストラクター参照で使用される::new
形式は次のとおりです。
public class FunctionRefTest06 {
public static void main(String[] args) {
Supplier<Person> sup = ()->{
return new Person();};
System.out.println(sup.get());
// 然后通过 方法引用来实现
Supplier<Person> sup1 = Person::new;
System.out.println(sup1.get());
BiFunction<String,Integer,Person> function = Person::new;
System.out.println(function.apply("张三",22));
}
}
配列::コンストラクター
public static void main(String[] args) {
Function<Integer,String[]> fun1 = (len)->{
return new String[len];
};
String[] a1 = fun1.apply(3);
System.out.println("数组的长度是:" + a1.length);
// 方法引用 的方式来调用数组的构造器
Function<Integer,String[]> fun2 = String[]::new;
String[] a2 = fun2.apply(5);
System.out.println("数组的长度是:" + a2.length);
}
メソッド参照は、特定の状況を満たすラムダ式の略語です。これにより、ラムダ式がより合理化され、ラムダ式の略語として理解することもできます。ただし、メソッド参照は、存在する既存のメソッドのみを参照できることに注意してください。