まとめ
私が自由だったとき、私はJVMで走っているグルーヴィーとスカラを学ぶのに時間をかけて、彼らが以前のバージョンのJavaよりもはるかに慎重にヌルを処理することがわかりました。 Java 8では、オプションは機能的なプログラミングヌル処理のための非常にエレガントなソリューションを提供します。この記事では、Javaでのnullの長年の悪い取り扱いについて説明し、その後、オプションの使用を導入してJava機能プログラミングを実装します。
その年に私たちを悩ませたヌル
Javaの世界には伝説があります。NullPointerの例外を本当に理解している場合にのみ、資格のあるJava開発者と見なすことができます。 Javaキャラクターのキャリアでは、毎日さまざまなヌル処理に遭遇します。次のようなコードを毎日繰り返し書くことができます。
if(null!= obj1){if(null!= obje2){//何か}}}あなたが少しビジョンを持っているなら、Javaerはいくつかのきれいなことをして、Nullを判断する方法を見つけるでしょう:
boolean checknotnull(object obj){return null == obj? false:true; } void do(){if(checknotnull(obj1)){if(checknotnull(obj2)){//何か}}}}次に、質問が再び来ます。ヌルが空の文字列を表している場合、「」とはどういう意味ですか?
それから慣性思考は、「」とヌルはどちらも空の文字列コードですか? null値を単純にアップグレードしました:
boolean checknotblank(object obj){return null!= obj &&! ""。equals(obj)? True:false; } void do(){if(checknotblank(obj1)){if(checknotnull(obj2)){//何か}}}}時間がある場合は、現在のプロジェクトまたは過去のコードで書いたコードの量と、上記のコードに似ていることを確認できます。
あなたが質問について真剣に考えたのだろうか:ヌルはどういう意味ですか?
思い出して、以前のグラミングキャリアでjava.lang.nullpointerexceptionの例外に何回遭遇しましたか? nullpointerexceptionは、キャプチャする必要のないruntimeexceptionレベルの例外です。誤って処理すると、生産ログのnullpointerexceptionによって引き起こされるさまざまな例外スタック出力がよく見られます。また、この例外スタック情報に基づいて、問題の原因となる場所ではないため、問題の原因を見つけることはできません。これが問題を引き起こしたからです。このヌルが生成された場所をより深く見つける必要があり、現時点ではログを追跡できないことがよくあります。
ヌル値が生成される場所が私たち自身のプロジェクトコードにないことが多いことがさらに悲劇的であることがあります。これには、より恥ずかしい事実があります - さまざまな品質のさまざまなサードパーティインターフェイスを呼び出すと、インターフェイスが偶然にヌルを返すかどうかを判断するのは困難です...
nullの以前の認知問題に戻ります。多くのJavaersは、ヌルは「何もない」または「価値は存在しない」とは信じています。この慣性思考によれば、私たちのコードロジックは次のとおりです。あなたは私のインターフェイスを呼び出し、私に与えるパラメーターに従って対応する「値」を返します。この条件が対応する「値」を見つけることができない場合、もちろん、私はあなたに「もの」がないというnullを返します。非常に伝統的で標準的なJavaコーディングスタイルで書かれている次のコードを見てみましょう。
クラスmyEntity {int id;文字列名; string getname(){return name; }} // MainPublic Class Test {public static void main(string [] args)最終的なmyEntity = getMyEntity(false); system.out.println(myentity.getname()); } private getMyEntity(boolean issuc){if(issuc){return new myentity(); } else {return null; }}}このコードは非常にシンプルであり、毎日のビジネスコードはこれよりもはるかに複雑ですが、実際、このルーチンに従って多数のJavaコードが記述されています。商品の使用方法を知っている人は、最終的にnullpointerexceptionを間違いなく投げることを一目で見ることができます。ただし、ビジネスコードを書くとき、この可能なヌルに対処することはめったに考えません(APIドキュメントは非常に明確に記述され、場合によってはヌルを返すかもしれませんが、テストの特定の段階に到達するまで、コードを書き始める前にAPIドキュメントを慎重に読み取ることを確認しますか?)。
// MainPublic Class Test {public static void main(string [] args)最終的なmyEntity = getMyEntity(false); if(null!= myentity){system.out.println(myentity.getname()); } else {system.out.println( "error"); }}}過去数年について慎重に考えてください、私たちは皆これをやったことがありますか?いくつかのヌルの問題をテスト段階まで発見できない場合、問題は現在です - それらの複雑でよく構造化されたビジネスコードで適切に処理されていないnullはいくつありますか?
プロジェクトの成熟度と厳密さは、nullを扱うときにしばしば見ることができます。たとえば、GuavaはJDK1.6の前にエレガントなヌル処理方法を提供しました。これは、スキルがどれほど深いかを示しています。
幽霊のようなヌルは、私たちが進行するのを妨げます
あなたが従来のオブジェクト指向の開発に焦点を当てているJavaerである場合、Nullによって引き起こされるさまざまな問題に慣れている可能性があります。しかし、何年も前、偉大な神はヌルが穴だと言っていました。
トニー・ホール(この男が誰なのかわからないの?自分でチェックしてください)はかつて言った:「私はそれを私の10億ドルの間違いと呼んでいます。それは1965年のヌルの参照の発明でした。単に、それが非常に簡単に実装できたからといって、ヌルの参照を入れる誘惑に抵抗できませんでした。」 (一般的な意味は、「私はそれをヌルの発明と呼んでいます。1965年のコンピューターの荒野では、空の参照が実装が簡単すぎたので、ヌルポインターを発明する誘惑に抵抗できませんでした。」
次に、他の問題が導入する他の問題を見てみましょう。
次のコードをご覧ください。
string address = person.getCountry()。getProvince()。getCity();
いくつかの機能的な言語(Haskell、Erlang、Clojure、Scalaなど)をプレイしている場合、上記は非常に自然な執筆方法です。もちろん、上記の執筆方法はJavaを使用して実装できます。
しかし、可能なすべてのヌルの例外を完全に処理するには、このエレガントな機能プログラミングパラダイムをこれに変更する必要があります。
if(person!= null){country country = person.getCountry(); if(country!= null){州省= country.getProvince(); if(province!= null){address = provence.getCity(); }}}すぐに、高品質の機能プログラミングJava8は10年前に戻りました。このようなネストされた判断は依然として些細なものであり、コードの量を増やし、不可分です。発生する可能性が高い:ほとんどの場合、人々は発生する可能性のあるヌルを判断することを忘れます。長年コードを書いていた高齢者でさえも例外ではありません。
層ごとにネストされたnull処理の上記のセクションは、長い間批判されている伝統的なJavaの一部でもあります。初期のJavaバージョンを啓発言語として使用する場合、get-> null-> returnが長い間影響を与える場合(エンティティ指向の開発と呼ばれる外国コミュニティで覚えておいてください)。
オプションを使用してJava機能プログラミングを実装します
さて、あらゆる種類の問題について話した後、私たちは新しい時代に入ることができます。
Java SE 8バージョンの発売のずっと前に、他の同様の機能開発言語には独自のさまざまなソリューションがありました。 Groovyのコードは次のとおりです。
string version = computer?.getSoundcard()??。getUsb()??。getVersion(): "unkonwn";
Haskellは、null値を処理するためにタイプクラス識別子を使用します。 Multi-Paradigm Development Languageとして知られるScalaは、nullのラッピングと処理のために、おそらく同様のオプションを提供します。
Java8はJava.util.optional <t>を導入して、機能プログラミングのヌル問題を処理します。オプションの<t>の処理のアイデアは、HaskellおよびScalaのアイデアに似ていますが、いくつかの違いがあります。 Javaコードの次の例を見てみましょう。
public class test {public static void main(string [] args){final string text = "hallo world!"; optional.ofnullable(text)// show optional shell.map(test :: print).map(test :: print).ifpresent(system.out :: println); optional.ofnullable(text).map(s-> {system.out.println(s); return s.substring(6);}).map(s-> null)// return null .ifpresent(system.out :: println); } // str [5] private static string print(string str){system.out.println(str); str.substring(6); }} // consol output // num1:hallo world!// num2:world!// num3:// num4:hallo world!(JDK8をインストールする必要がある場合、上記のコードをIDEにコピーできます。)
上記のコードで2つのオプションが作成され、実装された関数は基本的に同じです。どちらもストリングシェルとしてオプションを使用して文字列を切り捨てます。処理中にヌル値が発生した場合、処理は継続されなくなります。 s-> nullが2番目のオプションに表示された後、その後のifpresentが実行されなくなることがわかります。
出力// num3:に注意してください。つまり、「」文字はnullではなく出力です。
オプションは、コードを次のように変更するなど、さまざまな状況を処理するための豊富なインターフェイスを提供します。
public class test {public static void main(string [] args){final string text = "hallo world!"; System.out.Println(Lowercase(Text)); // Method One Lowercase(null、System.out :: println); // Method Two} private static String lowercase(string str){return optional.ofnullable(str).map(s-> s.tolowarcase())。 } private static void小文字(String str、Consumer <string> Consumer){Consumer.Accept(Lowercase(str)); }} // output // hallo java!// nanこのようにして、文字列を動的に処理できます。値がいつでもnullであることが判明した場合、orelseを使用してプリセットのデフォルト「nan」を返します。
一般に、任意のデータ構造をオプションでラップし、いつでも表示される可能性のあるヌルを心配することなく、機能的な方法で処理できます。
先ほど前述したgetprovince()。getProvince()。getProvince()をどのように処理するかを見てみましょう。
最初の方法は、以前のエンティティを変更しないことです。
java.util.optional; public class test {public static void main(string [] args){system.out.println(optional.ofnullable(new Person()).map(x-> x.country).map(x-> x.provinec).map(x-> x.city(x-> x.name)。 .orelse( "unkonwn")); }} class person {country Country;} class country {province provisionec;} class province {city city;} class city {string name;}ここでは、オプションは毎回シェルが返されるときに使用されます。特定の位置がnullを返す場合、「unkonwn」が得られます。
2番目の方法は、すべての値をオプションで定義することです。
Java.util.optional; public class test {public static void main(string [] args){system.out.println(new person().country.flatmap(x-> x.provinec).flatmap(stavince :: getcity).flatmap(x -name).orelse).orelse(x -name).orelse "); }} class person {optional <country> country = optional.empty();} class country {optional <butince> provisionc;} class bevince {optional <city> city; optional <city> getCity(){// for :: return City; }} class city {optional <string> name;}最初の方法は、変更なしで既存のJavabean、エンティティ、またはPOJAとスムーズに統合でき、サードパーティのインターフェイス(スプリングビーンズなど)により簡単に統合できます。最初のオプションの方法は、主な方法として使用することをお勧めします。結局のところ、チームの全員が、オプションを使用して各GET/セットの目的を理解できるわけではありません。
オプションは、データをフィルタリングするためのフィルター方法も提供します(実際、Java 8のストリームスタイルのインターフェイスがフィルターメソッドを提供します)。たとえば、過去には、値が存在し、対応する処理が行われたと判断しました。
if(province!= null){city city = provence.getCity(); if(null!= city && "guangzhou" .equals(city.getname()){system.out.println(city.getName());} else {system.out.println( "unkonwn");}}これで変更できます
optional.ofnullable(stavince).map(x-> x.city).filter(x-> "guangzhou" .equals(x.getname())).map(x-> x.name).orelse( "unkonw");
この時点で、機能プログラミングの導入はオプションを使用して完了します。上記の方法に加えて、オプションは、より多くのニーズ、Orelseget、Orelsethrowなどに基づいたメソッドも提供します。OrelsegetはNull値のためにNull Pointerの例外をスローし、OrelsethrowはNullが発生したときにユーザー定義の例外をスローします。 APIドキュメントを表示して、すべての方法の詳細を確認できます。
最後に書かれています
オプションは、Java機能プログラミングの氷山の一角にすぎません。 Java8機能プログラミングの有効性を真に理解するには、Lambda、Stream、FunctionInterfaceなどの機能を組み合わせる必要があります。私はもともと、いくつかのオプションのソースコードと操作原則を導入したかったのですが、オプション自体にはコードがほとんどなく、APIインターフェイスがあまりありません。あなたがそれについて注意深く考えるなら、言うことは何もありません、そしてあなたはそれを省略します。
オプションはエレガントですが、個人的には効率性の問題があると感じていますが、まだ検証されていません。誰かがデータを持っている場合は、私に知らせてください。
私は「機能的なプログラミングサポーター」ではありません。チームマネージャーの観点から見ると、小さな学習の難易度が高まるごとに、人員使用のコストとチームの相互作用が高くなります。伝説と同じように、LISPはC ++よりもコードが30倍少なくなり、開発がより効率的ですが、国内の従来のIT会社が実際にLISPを使用してプロジェクトを行う場合、どこに行くべきか、LISPを使用する人を獲得するのにどれくらいの費用がかかりますか?
しかし、私は誰もが機能的なプログラミングのアイデアを学び、理解することを強くお勧めします。特に、以前はJavaに侵略されていて、Java8がどのような変化をもたらすかわからなかった開発者は、Java8が良い機会です。また、現在のプロジェクトに新しいJava8機能を導入することも奨励されています。長い間協力しており、古代のプログラミング言語は常に新しい活力を注入する必要があります。そうしないと、前進しないと退却します。
上記は、Javaのオプション情報のコレクションです。今後も関連情報を追加し続けます。このウェブサイトへのご支援ありがとうございます!