Java 8が準備していること

新しい方法でニュースとコードを見てみましょう。

それでは、リストから始めましょう。

リストがあるとします。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); 


昔の私たちがどのように反復したかを思い出してください:
 for (int i = 0; i < numbers.size(); i++){ System.out.println(numbers.get(i)); } 


すべてが素晴らしいですが、つまずいて<の代わりに<=を置くか、0の代わりに1から始めるのは非常に簡単です。上記のコードでは、メカニズムを完全に制御し、すべての可動部分を念頭に置いています。 多くの場合、これは良いことです。Java5では、砂糖を追加しただけで誰もそれを採用しませんでした。

 for(int num:numbers){ System.out.println(num); } 


Java 8では、彼らはまだ何も取りませんが、「宣言的」アプローチを提供します。つまり、やりたいことを宣言し、すべてのメカニズムをJVMに配置します。

  numbers.forEach(value -> System.out.println(value)); 


この例ではラムダ式を使用していることに注意してください。 次の段落で彼について。 多くの人がすでにforEachを多くの言語とライブラリで見ています。 したがって、forEachを使用すると、「最初から始めて最後で終わり、1つずつ反復して各要素を使用する」のではなく、「ここにコレクションがあり、この式をそのすべての要素に適用します」(宣言的アプローチ)を1行で表現できます。

ラムダ式について。

匿名クラスを関数に置き換えることができる非常においしい革新。

すでに上記の例を考えてみましょう。
  numbers.forEach(value -> System.out.println(value)); 


ラムダ式がない場合、この例は次のようになります。
 numbers.forEach(new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.println(integer); } @Override public Consumer<Integer> andThen(Consumer<? super Integer> after) { return null; } }); 


複雑ですね。 しかし、単純な1行の式に戻ります。ここでは、何かを単純化することができます。他の変数が存在しないことが既に明らかである場合、なぜ2回値に言及する必要があります。
 numbers.forEach(System.out::println); 


はい、はい、メソッドを関数として渡しました(*)。 そこで、「ここに方法があります。ループで適用してください。」

以下は、匿名クラスを関数で置き換えるいくつかの例です。

ストリーム作成:
 new Thread(SomeClass::runSomething).start(); 


コンパレーターソート
 Collections.sort(numbers, (o1, o2)-> o2.compareTo(o1)); 


コレクションフレームワークの変更

ラムダ式を理解したら、Collections Frameworkの最新版に進みます。 リスト内のすべての数値の合計に2を掛けて計算する必要があるとします。 考え直すことなく、コードを作成します。

  List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); int sum = 0; for (int num : numbers) { sum += num * 2; } 


それでは、宣言的なアプローチに移りましょう。
 int result = numbers.stream(). mapToInt(value->value*2). sum(); 

ちょっと待ってください、このmap-reduceではありませんか? 彼が一番です。 順番に分析します。 したがって、mapToIntはマップ操作を実行し、その結果、要素は2回になります。 sumは、整数に対してのみ使用可能な縮小変換です。

コードを変更し、奇数のもののみを処理し、奇数のものをフィルタリングする命令を受け取ったとします。
  System.out.println(numbers.stream(). filter(value -> value % 2 == 0). mapToInt(value -> value * 2). sum()); 


反対に、奇数カウント、さらには破棄:
  System.out.println(numbers.stream(). filter(value -> value % 2 != 0). mapToInt(value -> value * 2). sum()); 


別の新しい言語機能

私たちは、インターフェイスが「何をするのか」を教えてくれますが、それ自体では何もしないという事実に慣れています。 Java 8では、インターフェースは時々何かをします。

以下に例を示します。
 public interface IFly { public void takeOff(); public default void cruise() { System.out.println("IFly.cruise"); }; public void turn(); public void land(); } 


C ++でプログラムを作成し、BjörnStaustrupを読んだ人は、「ダイヤモンドの問題はどうですか?」という質問をします。 質問は興味深いです。 そして答えがあります。

クラスが2つのインターフェイスを継承し、それぞれにデフォルトのメソッドがあるとします。 コンパイル中にエラーが発生します。

  public interface A { default void hello() { System.out.println("Hello World from A"); } } public interface B { default void hello() { System.out.println("Hello World from B"); } public class D implements A,B {} 


別の例を見てみましょう:三角形
  public interface A { default void hello() { System.out.println("Hello World from A"); } } public interface B extends A { default void hello() { System.out.println("Hello World from B"); } } public class C implements B, A { public static void main(String... args) { new C().hello(); } } 


この場合、階層内で最も近いもの、つまりインターフェースBが優先されます。インターフェースAのメソッドを使用する場合は、明示的に指定する必要があります

 A.super.hello(); 


3番目の例を見てみましょう:抽象クラスとインターフェイスには競合するメソッドがあります。 ルール-クラスは常に勝ちます。

したがって、問題は解決されます。


さらにいくつかのグッズ


Base64、廃止されたsun.misc.Base64についてコンパイラがひどいメッセージをくれた時間と、一見単純なことのためにApachevライブラリを使用しなければならなかった時間。
これで問題は解決されました:java.util.Base64
 Base64.getEncoder().encode(new byte[]{1, 2, 3, 4, 5}); 


新しい日付と時刻のAPI。 古き良きGregorianCallendarを想像できない場合は、新しいClock、Time、LocalTimeクラスを試すことができます

  import java.time.LocalDate; import java.time.Period; ... LocalDate time = LocalDate.now(); Period period = Period.ofDays(2); LocalDate newDate = time.plus(period); System.out.println("year:"+newDate.getYear()); System.out.println("month:"+newDate.getMonth()); System.out.println("day:"+newDate.getDayOfMonth()); 

Source: https://habr.com/ru/post/J203026/


All Articles