Java 8インタビューの質問(回答)

Java 8インタビューの質問(回答)

1. 前書き

この記事では、インタビュー中にポップアップ表示される可能性のあるJDK8関連の質問のいくつかを検討します。

Java 8は、新しい言語機能とライブラリクラスが満載されたプラットフォームリリースです。 これらの新機能のほとんどは、よりクリーンでコンパクトなコードの実現に向けられており、一部の機能はJavaでサポートされていない新しい機能を追加します。

参考文献:

Javaインタビューのメモリ管理に関する質問(+回答)

メモリー管理に関連した一般的なインタビューの質問と、もちろん回答のセット。

Javaコレクションインタビューの質問

一連の実用的なコレクション関連のJavaインタビューの質問

2. Java8の一般知識

Q1. Java 8で追加された新機能は何ですか?

Java 8にはいくつかの新機能が付属していますが、最も重要なものは次のとおりです。

  • Lambda Expressions-アクションをオブジェクトとして扱うことを可能にする新しい言語機能

  • Method References-名前を使用してメソッドを直接参照することにより、ラムダ式の定義を有効にします

  • Optional-オプション性を表現するために使用される特別なラッパークラス

  • Functional Interface –最大1つの抽象メソッドを持つインターフェース。Lambda式を使用して実装を提供できます。

  • Default methods-抽象メソッドに加えてインターフェイスに完全な実装を追加する機能を提供します

  • Nashorn, JavaScript Engine-JavaScriptコードを実行および評価するためのJavaベースのエンジン

  • Stream API-オブジェクトのコレクションを機能的に処理できるようにする特別なイテレータクラス

  • Date API-改善された不変のJodaTimeに触発されたDate API

これらの新機能に加えて、コンパイラーとJVMレベルの両方で、多くの機能強化が内部で行われます。

3. メソッド参照

Q1. メソッドリファレンスとは何ですか?

メソッド参照は、メソッドを呼び出すことなくメソッドを参照するために使用できるJava 8構成体です。 メソッドをラムダ式として扱うために使用されます。 それらは、一部のラムダの冗長性を減らすための構文糖としてのみ機能します。 この方法では、次のコード:

(o) -> o.toString();

になることができる:

Object::toString();

メソッド参照は、クラス名またはオブジェクト名とメソッド名を区切る二重コロンで識別できます。 コンストラクター参照など、さまざまなバリエーションがあります。

String::new;

静的メソッドのリファレンス:

String::valueOf;

バインドされたインスタンスメソッドリファレンス:

str::toString;

非バインドインスタンスメソッドリファレンス:

String::toString;

this linkおよびthis oneを実行すると、完全な例を含むメソッド参照の詳細な説明を読むことができます。

Q2. String :: Valueof式の意味は何ですか?

これは、StringクラスのvalueOfメソッドへの静的メソッド参照です。

4. オプション

Q1. Optionalとは何ですか? どのように使用できますか?

Optionalは、オプションの値をカプセル化するJava8の新しいクラスです。 値があるかどうか。 これはオブジェクトのラッパーであり、0個または1個の要素のコンテナと考えることができます。

Optionalには、ラップされたnullの代わりに特別なOptional.empty()値があります。 したがって、多くの場合、null許容値の代わりに使用してNullPointerExceptionを取り除くことができます。

Optionalhereに関する専用記事を読むことができます。

作成者によって設計されたOptionalの主な目的は、以前はnullを返すメソッドの戻り値の型にすることでした。 このようなメソッドでは、戻り値をチェックするための定型コードを記述する必要があり、場合によっては防御チェックの実行を忘れることがあります。 Java 8では、Optionalの戻り値の型では、nullまたはnull以外のラップされた値を異なる方法で処理する必要があります。

たとえば、Stream.min()メソッドは、値のストリームの最小値を計算します。 しかし、ストリームが空の場合はどうでしょうか? Optionalがなかった場合、メソッドはnullを返すか、例外をスローします。

ただし、Optional.empty()の可能性があるOptional値を返します(2番目の場合)。 これにより、このようなケースを簡単に処理できます。

int min1 = Arrays.stream(new int[]{1, 2, 3, 4, 5})
  .min()
  .orElse(0);
assertEquals(1, min1);

int min2 = Arrays.stream(new int[]{})
  .min()
  .orElse(0);
assertEquals(0, min2);

OptionalはScalaのOptionのような汎用クラスではないことに注意してください。 エンティティクラスのフィールド値として使用することはお勧めしません。これは、Serializableインターフェイスを実装していないことで明確に示されています。

5. 機能的インターフェース

Q1. 標準ライブラリの機能インターフェイスのいくつかを説明します。

java.util.functionパッケージには多くの機能インターフェイスがあり、より一般的なインターフェイスには次のものが含まれますが、これらに限定されません。

  • Function – 1つの引数を取り、結果を返します

  • Consumer – 1つの引数を取り、結果を返しません(副作用を表します)

  • Supplier –引数を取らず、結果を返します

  • Predicate – 1つの引数を取り、ブール値を返します

  • BiFunction – 2つの引数を取り、結果を返します

  • BinaryOperator –これはBiFunctionに似ており、2つの引数を取り、結果を返します。 2つの引数と結果はすべて同じ型です

  • UnaryOperator –これはFunctionに似ており、単一の引数を取り、同じタイプの結果を返します。

機能インターフェイスの詳細については、記事“Functional Interfaces in Java 8”を参照してください。

Q2. 機能的インターフェースとは? 関数型インターフェースを定義する規則は何ですか?

関数型インターフェースは、1つの抽象メソッド(defaultメソッドはカウントされません)を超えないインターフェースです。

そのようなインターフェイスのインスタンスが必要な場合は、代わりにLambda式を使用できます。 より正式に言えば、Functional interfacesはラムダ式とメソッド参照のターゲットタイプを提供します。

このような式の引数と戻り値の型は、単一の抽象メソッドの引数と戻り型に直接一致します。

たとえば、Runnableインターフェイスは機能インターフェイスであるため、次の代わりに次のようになります。

Thread thread = new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello World!");
    }
});

あなたは単にすることができます:

Thread thread = new Thread(() -> System.out.println("Hello World!"));

関数型インターフェースは通常、@FunctionalInterface注釈で注釈が付けられます。これは有益であり、セマンティクスに影響を与えません。

6. デフォルトのメソッド

Q1. デフォルトの方法とは何ですか?いつ使用しますか?

デフォルトのメソッドは、実装を備えたメソッドであり、インターフェースで見つけることができます。

デフォルトのメソッドを使用して、インターフェースを既に実装しているクラスとの後方互換性を維持しながら、インターフェースに新しい機能を追加できます。

public interface Vehicle {
    public void move();
    default void hoot() {
        System.out.println("peep!");
    }
}

通常、新しい抽象メソッドがインターフェイスに追加されると、実装するクラスはすべて、新しい抽象メソッドを実装するまで壊れます。 Java 8では、この問題はデフォルトのメソッドを使用することで解決されました。

たとえば、CollectionインターフェイスにはforEachメソッド宣言がありません。 したがって、このようなメソッドを追加すると、コレクションAPI全体が単純に破損します。

Java 8ではデフォルトのメソッドが導入されているため、Collectionインターフェースは、このインターフェースを実装するクラスが同じものを実装する必要なしに、forEachメソッドのデフォルトの実装を持つことができます。

Q2. 次のコードはコンパイルされますか?

@FunctionalInterface
public interface Function2 {
    public V apply(T t, U u);

    default void count() {
        // increment counter
    }
}

Yes. コードは、単一の抽象メソッドのみを定義する機能インターフェイス仕様に従っているため、コンパイルされます。 2番目のメソッドcountは、抽象メソッドの数を増やさないデフォルトのメソッドです。

7. ラムダ式

Q1. ラムダ式とは何ですか?それは何に使用されますか

非常に簡単に言えば、ラムダ式は、参照してオブジェクトとして渡すことができる関数です。

ラムダ式は、Javaで機能スタイル処理を導入し、コンパクトで読みやすいコードの作成を容易にします。

このため、ラムダ式は、メソッド引数としての匿名クラスの自然な置き換えです。 主な用途の1つは、機能的なインターフェイスのインライン実装を定義することです。

Q2. ラムダ式の構文と特徴を説明する

ラムダ式は、2つの部分で構成されます。下のように、前方矢印で区切られたパラメーター部分と式部分です。

params -> expressions

ラムダ式には次の特性があります。

  • Optional type declaration –ラムダの左側でパラメーターを宣言する場合、コンパイラーが値からパラメーターを推測できるため、パラメーターを宣言する必要はありません。 したがって、int param → …param →…はすべて有効です

  • Optional parentheses – 1つのパラメーターのみが宣言されている場合、それを括弧で囲む必要はありません。 これは、param → …(param) → …がすべて有効であることを意味します。 ただし、複数のパラメーターが宣言されている場合は、括弧が必要です

  • Optional curly braces –式の部分にステートメントが1つしかない場合は、中括弧は必要ありません。 これは、param – > statementparam – > \{statement;}がすべて有効であることを意味します。 ただし、複数のステートメントがある場合は中括弧が必要です

  • Optional return statement –式が値を返し、中括弧で囲まれている場合、returnステートメントは必要ありません。 つまり、(a, b) – > \{return a+b;}(a, b) – > \{a+b;}の両方が有効です

ラムダ式の詳細については、this linkおよびthis oneに従ってください。

8. Nashorn Javascript

Q1. Java8のNashornとは何ですか?

Nashornは、Java8に同梱されているJavaプラットフォーム用の新しいJavascript処理エンジンです。 JDK 7まで、Javaプラットフォームは同じ目的でMozilla Rhinoを使用していました。 Javascript処理エンジンとして。

Nashornは、ECMAの正規化されたJavaScript仕様へのコンプライアンスを改善し、以前のバージョンよりも優れたランタイムパフォーマンスを提供します。

Q2. JJSとは?

Java 8では、jjsは、コンソールでJavascriptコードを実行するために使用される新しい実行可能ファイルまたはコマンドラインツールです。

9. ストリーム

Q1. ストリームとは コレクションとどう違うのですか?

簡単に言えば、ストリームはイテレータであり、その役割は含まれる各要素に適用するアクションのセットを受け入れることです。

The streamは、集計操作をサポートするコレクションなどのソースからのオブジェクトのシーケンスを表します。 これらは、コレクション処理を簡単かつ簡潔にするために設計されました。 コレクションとは異なり、反復のロジックはストリーム内に実装されているため、mapflatMapなどのメソッドを使用して宣言型処理を実行できます。

もう1つの違いは、Stream APIが流暢であり、パイプライン化が可能であることです。

int sum = Arrays.stream(new int[]{1, 2, 3})
  .filter(i -> i >= 2)
  .map(i -> i * 3)
  .sum();

また、コレクションとのもう1つの重要な違いは、ストリームが本質的に遅延ロードおよび処理されることです。

Q2. 中間操作と端末操作の違いは何ですか?

ストリーム操作は、ストリームを処理するためにパイプラインに結合されます。 すべての操作は、中間または端末のいずれかです。

中間操作は、Stream自体を返す操作であり、ストリームでさらに操作できるようにします。

これらの操作は常に怠zyです。 それらは呼び出しサイトでストリームを処理しません。中間操作は、端末操作がある場合にのみデータを処理できます。 中間操作には、filtermap、およびflatMapがあります。

ターミナル操作はパイプラインを終了し、ストリーム処理を開始します。 ストリームは、端末操作呼び出し中にすべての中間操作を通過します。 ターミナル操作には、forEachreduce, Collect、およびsumが含まれます。

この点を理解するために、副作用のある例を見てみましょう。

public static void main(String[] args) {
    System.out.println("Stream without terminal operation");

    Arrays.stream(new int[] { 1, 2, 3 }).map(i -> {
        System.out.println("doubling " + i);
        return i * 2;
    });

    System.out.println("Stream with terminal operation");
        Arrays.stream(new int[] { 1, 2, 3 }).map(i -> {
            System.out.println("doubling " + i);
            return i * 2;
    }).sum();
}

出力は次のようになります。

Stream without terminal operation
Stream with terminal operation
doubling 1
doubling 2
doubling 3

ご覧のとおり、中間操作は端末操作が存在する場合にのみトリガーされます。

Q3. MapflatMapのストリーム操作の違いは何ですか?

mapflatMapの間で署名に違いがあります。 一般的に、map演算は戻り値を通常の型にラップしますが、flatMapはラップしません。

たとえば、Optionalでは、map操作はOptional<String>タイプを返し、flatMapStringタイプを返します。

そのため、マッピング後、値を取得するためにオブジェクトをラップ解除(「フラット化」)する必要がありますが、フラットマッピング後は、オブジェクトがすでにフラット化されているため、そのような必要はありません。 同じ概念がStreamのマッピングとフラットマッピングに適用されます。

mapflatMapはどちらも、関数を受け取り、この関数をストリームのすべての要素に適用する中間ストリーム操作です。

違いは、mapの場合、この関数は値を返しますが、flatMapの場合、この関数はストリームを返すことです。 flatMap操作は、ストリームを1つに「フラット化」します。

これは、ユーザーの名前と電話のリストのマップを取得し、flatMapを使用してすべてのユーザーの電話のリストに「フラット化」する例です。

Map> people = new HashMap<>();
people.put("John", Arrays.asList("555-1123", "555-3389"));
people.put("Mary", Arrays.asList("555-2243", "555-5264"));
people.put("Steve", Arrays.asList("555-6654", "555-3242"));

List phones = people.values().stream()
  .flatMap(Collection::stream)
    .collect(Collectors.toList());

Q4. Java 8のストリームパイプラインとは何ですか?

ストリームパイプライン化は、操作をチェーン化する概念です。 これは、ストリームで発生する可能性のある操作を、中間操作と端末操作の2つのカテゴリに分割することで実行されます。

各中間操作は、実行時にStream自体のインスタンスを返すため、処理パイプラインを形成するデータを処理するために、任意の数の中間操作を設定できます。

次に、最終値を返し、パイプラインを終了する端末操作が必要です。

10. Java8の日付と時刻のAPI

Q1. Java8の新しいDateand TimeAPIについて教えてください

Java開発者にとって長年の問題は、通常の開発者が必要とする日付と時刻の操作に対するサポートが不十分であることです。

java.util.DateSimpleDateFormatterなどの既存のクラスはスレッドセーフではないため、ユーザーに同時実行の問題が発生する可能性があります。

貧弱なAPI設計も、古いJava Data APIの現実です。 簡単な例を次に示します。java.util.Dateの年は1900から始まり、月は1から始まり、日は0から始まります。これはあまり直感的ではありません。

これらの問題および他のいくつかの問題により、Joda-Timeなどのサードパーティの日付と時刻のライブラリが人気を博しています。

これらの問題に対処し、JDKでより良いサポートを提供するために、これらの問題のない新しい日付と時刻のAPIが、パッケージjava.timeでJava SE8用に設計されました。

11. 結論

この記事では、Java 8に偏った技術面接の質問について、いくつかの非常に重要な質問について説明しました。 これは決して完全なリストではありませんが、Java 8の各新機能に登場する可能性が最も高いと思われる質問のみが含まれています。

始めたばかりの場合でも、特にJavaが履歴書に強く登場する場合は、Java8を知らないことは面接に行くのに良い方法ではありません。 したがって、これらの質問への回答を理解し、場合によってはより多くの調査を行うために時間をかけることが重要です。

インタビューで頑張ってください。