Java Puzzlers NG S02さらに玠晎らしい、玠晎らしい

Tagir Valeev lany ずBaruch Sadogursky jbaruch は、Javaパズルの新しいコレクションを䜜成し、急いでそれらを共有しおいたす。


この蚘事は、秋の䌚議JPoint 2017でのスピヌチのデコヌドに基づいおいたす。Java8の地平線でJava 8ずかろうじお迫り来る謎がいく぀あるかを瀺しおいたす。私たちを混乱させるために。

圌らが話しおいるこずはすべお、それぞれ最新バヌゞョンのJava 8および9で動䜜するはずです。 私たちはチェックしたした-すべおが正盎であるようですそれが曞かれおいるように、これはそれがどのように動䜜するかです。

念のために、著者に぀いおのいく぀かの蚀葉は、あなたが既によく知っおいるず思いたすが、BaruchはJFrogでDeveloper Relationsに埓事しおおり、TagirはIntelliJ IDEA開発者であり、StreamExラむブラリの䜜成者です。

Javaパズルの番号1銀行を飛び越える方法


りォヌムアップするために、最初の謎解きを求めたす。未知のアメリカのハッカヌが銀行を飛び越えようずしおいたす。



基本的に、銀行のロゞックをJava Semaphoreにマッピングしおいたす。 Semaphoreコンストラクタヌには、初期バランスがありたす。 -42オヌバヌドラフトから開始し、セマフォメ゜ッドを銀行取匕メ゜ッドにマッピングしたす。 ぀たり、 drainPermitsこれは「銀行からすべおのお金を取る」こずavailablePermitsが、 availablePermits 「残高を確認する」こずです。

 public class PerfectRobbery {   private Semaphore bankAccount = new Semaphore(-42);   public static void main(String[] args) {           PerfectRobbery perfectRobbery = new PerfectRobbery();           perfectRobbery.takeAllMoney();           perfectRobbery.checkBalance();  }  public void takeAllMoney(){       bankAccount.drainPermits(); } public void checkBalance(){        System.out.println(bankAccount.availablePermits()); } } 

そしお、いく぀かのロゞックがありたす。 PerfectRobberyクラスでPerfectRobberyオブゞェクトを䜜成し、2぀のメ゜ッドを呌び出したす。銀行からすべおのお金を収集し、実際にすべおのお金を受け取ったこずを確認したす。

負の初期倀でセマフォを䜜成するにはどうすればよいですか これは最初の答えなので、玠晎らしい質問です。 そしお、圌のほかに、さらに3぀ありたす。

A. IllegalArgumentException負のバランスのセマフォを䜜成できたせん。
B. UnsupportedOperationException負のバランスのセマフォを䜜成できたすが、その䞊でdrainPermitsを呌び出すこずはできたせん。
C. 0-マむナスの残高のdrainPermitsは蚱可をれロのたたにしたす。
D. drainPermitsマむナスのバランスを持぀drainPermitsは、排出するものがないため、元のたたになりたす。

聎衆の投祚では、倧半がオプションDであり、正解はCであるこずが瀺されたした。

Javaのドキュメントでは、セマフォが負の倀をずるこずができるずいう蚘述を芋぀けるこずができたす。 さらに、 drainPermitsは䜿甚可胜なすべおの蚱可を返したす。



-42パヌミットがある堎合、どれくらい利甚できたすか 0が利甚可胜であるため、Sergey Kursenkoがバグをオヌプンし、次のように蚀いたした。 -42で利甚可胜な蚱可をドレヌンするず、利甚可胜な蚱可0があるため、-42のたたになりたす。-42から0をマヌゞするず、-42になりたす。



しかし、そこにあったのは、Doug Leeがコメントに参加しお蚀ったからです。 そのため、Javadocに行を远加しお「修正」したす。



Java Puzzler2シングルトヌン


さらに進みたしょう。 私たちからのちょっずしたヒントシングルトヌンを䜜成しないでください。シングルトヌンを飲むこずをお勧めしたす。



Java 7を芋おみたしょうemptyListを䜿甚しお空のリストを䜜成し、 emptyListを䜿甚しお空のむテレヌタヌを䜜成できたす。

 Collections.emptyList() == Collections.emptyList(); Collections.emptyIterator() == Collections.emptyIterator(); 

そしお質問は圌らはシングルトンですか 垞に同じオブゞェクトを返したすか 4぀の可胜な答えがありたす。

A. true / true-垞に戻りたす。
B. true / false-シングルトン-リストのみ。反埩子は毎回異なりたす。
C. false / true-むテレヌタヌ-シングルトン。新しいリストが毎回䜜成されたす。
D. false / false-これらはシングルトヌンではありたせん。

聎衆の投祚では、倧半がオプションBであり、正解はAであるこずが瀺されたした。ここで質問が始たりたす。 パズラヌが次に来たす。

Java 8に進みたしょう。空のオブゞェクトを返す新しいメ゜ッド、スプリッタヌずストリヌムがありたす。

 Spliterators.emptySpliterator() == Spliterators.emptySpliterator(); Stream.empty() == Stream.empty(); 

そしお、圌らのために質問を繰り返したしょう

A. true / true
B. true / false
C. false / true
D. false / false

聎衆の投祚では、倧半がオプションDであり、正解はBであるこずが瀺されたした。状態がないため、スプリッタヌはシングルトンになりたす。空のスプリッタヌを䜕回もバむパスしようずするこずができたす。 ただし、ストリヌムには状態があり、少なくずも2぀の芁玠で構成されおいたす。最初に、ストリヌムにcloseHandlerをハングさせるこずができたす。 それがシングルトンである堎合、ある堎所で1぀のハンドラヌを、別の堎所で別のハンドラヌを掛け、その埌䜕が起こるかわからないこずを想像しおください。 もちろん、すべおの空のストリヌムは、独立したフリヌである必芁がありたす。 第二に、ストリヌムは䞀床だけ䜿甚する必芁がありたす。 ストリヌムが再利甚される堎合、これを怜出しおIllegalStateExceptionをスロヌしたす。



Java Puzzler3同じリスト


次のパズルでは、やや奇劙な意味で「同䞀」ずいう蚀葉を䜿甚したす。 同䞀-これらは、内郚構造に関しお同じです。 これは、それらが等しい、たたは同じハッシュコヌドを持぀こずを意味するものではなく、参照のチェックに関連しおいるこずを意味するものでもありたせん。

2぀のリストの配列を䜜成したす。 Java 8ではsetAllメ゜ッドが導入されたため、すぐにすべおを埋めるこずができたす。 ArrayListコンストラクタで埋めたす。 2぀のリストで構成される配列を取埗したす。

 List[] twins = new List[2]; Arrays.setAll(twins, ArrayList::new); 

質問どのリストがありたすか 回答オプション

A.同䞀の空のリスト
B.同䞀の空でないリスト
C.同じ空のリストではない
D.同じではない空のリスト

聎衆の投祚では、倧半がオプションAであり、正解はCであるこずが瀺されたした。

最初に、 setAllはsupplier受け入れず、 inputInt Function受け入れたすinputInt Functionには、配列むンデックスが枡され、それに応じおこの配列むンデックスが匕数ずしお枡されたす。 空の匕数からではなく、initialCapacityからArrayListコンストラクタヌに自動的にマッピングしたす。 ぀たり、そこで送信されるこのむンデックスはどこにも登録されず、衚瀺されたせん。 これはGroovyの䞀郚です。私たちは䜕かを曞いおおり、䜕かをしおいるのですが、䜕を知っおいるのかわかりたせん。



ずころで、これのおかげでOutOfMemory飛ぶこずができたす。 10䞇の配列を䜜成した堎合、リストには10​​䞇の事前定矩された配列も含たれたす。

Java Puzzler No.4単䞀の抜象メ゜ッド


機胜的なむンタヌフェヌスを䜜成しおみたしょう。 たず、むンタヌフェむスを䜜成したすが、4぀のメ゜ッドを远加したす。そのうち3぀は抜象的です。 そしお、そこから別のむンタヌフェむスを継承し、機胜的にしたす。 コンパむルしたすか

 public interface <T> {      default void (String ) {                 System.out.println(); }  void (T songName);  void (T );  void (String ); } @FunctionalInterface public interface  extends <String> { } 

答えは次のずおりです。

A.䞀䜓䜕 「シングル」ずは、3぀ではなく1぀のメ゜ッドを意味したす
B. (T)メ゜ッドの問題(T) 、削陀しおも問題はあり(T)
C. をする方法に問題がある
倧䞈倫です。
D.最埌たで 重耇が厩壊し、 をために残されたす。

聎衆の投祚では、倧半がオプションDであり、正解はBであるこずが瀺されたした。実際、実装されおいないメ゜ッド はデフォルトの実装によっおブロックされおおらず、コンパむラは䜿甚するものを決定できたせん。 これはドキュメントに曞かれおいたす。むンタヌフェむスから、オヌバヌラむドず同等のシグネチャを持぀いく぀かの抜象メ゜ッドを継承できたす。 Tが文字列であるず刀断したずき、2぀のメ゜ッドは厩壊したした。 しかし、むンタヌフェむスがデフォルトのメ゜ッドを継承し、そのシグネチャが抜象メ゜ッドず同等のオヌバヌラむドである堎合、あいたいさが生じるため、これはコンパむル゚ラヌです。デフォルトの実装を䜿甚するかどうか。


Java蚀語仕様のスクリヌンショット

Javaパズル番号5銀行をハッキングする方法。 第二版


すべおの銀行゜フトりェアはJavaで曞かれおいたす。 Alfa BankはJava、Deutsche BankはJava、SberbankはJavaです。 すべおの銀行はJavaで蚘述したす。これはJavaの攻撃を意味し、倚くのホヌルがあり、ハッキングが容易で、その埌最倧の口座を芋぀けおそこからお金を匕き出したす。

 Set<String> accounts =      new HashSet<>(Arrays.asList("Gates", "Buffett", "Bezos", "Zuckerberg")); System.out.println("accounts= " + accounts); 

それらをたずめお印刷したしょう。 私たちがそれらを手に入れたのず同じ順序で芋るのだろうか

A.広告の順序は維持されたす
B.順序は䞍明ですが、実行の間に残りたす
C.順序は䞍明で、JVMを再起動するたびに倉わりたす
D.順序は䞍明で、印刷ごずに倉わりたす。

聎衆の投祚では、倧半がオプションBのものであり、これが正解であるこずが瀺されたした。 ハッシュの内郚がハッシュであり、ハッシュにはキヌがあるこずは誰もが知っおいたす。



これには䜕か関係がありたす そのため、アヌリヌアクセスリリヌスJava 9に切り替えおいたす銀行は垞にこれを行い、最新のものをすべお䜿甚したす。 Set.ofメ゜ッドがSet.ofに衚瀺されたため、ここですべおがより興味深いものになりSet.of 。そのため、この長いすべおの代わりに、簡単に曞くこずができたす。

 Set<String> accounts = Set.of("Gates", "Buffett", "Bezos", "Zuckerberg"); System.out.println("accounts= " + accounts); 

質問は同じたたです。セットに入れお印刷するず、アカりントを取埗したのず同じ順序で衚瀺されたすか

A.広告の順序は維持されたす
B.順序は䞍明ですが、実行の間に残りたす
C.順序は䞍明で、JVMを再起動するたびに倉わりたす
D.順序は䞍明で、印刷ごずに倉わりたす。

聎衆の投祚では、倧半がオプションCであり、これが正解であるこずが瀺されたした。 蚌拠がありたす。 9番目のJavaに登堎し、 JShellず呌ばれる新しい玠晎らしいものを利甚できたす。 このコヌドを詰め蟌み、䜕らかの順序を取埗し、繰り返し、異なる順序を取埗し、繰り返し、3番目の順序を取埗したす。 どのように機胜したすか



これは意図的に行われたす。 これは、同じSet.ofハッシュコヌドによっおテヌブル芁玠が蚈算される方法Set.of 。

 private int probe(Object pe) { int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length); while (true) {      E ee = elements[idx];      if (ee == null) {               return -idx - 1;      } else if (pe.equals(ee)) {               return idx;      } else if (++idx == elements.length) {               idx = 0;     } } } 

ハッシュコヌド^ SALTがあり、SALTはJVMの起動時に乱数で初期化される静的フィヌルドです。 これは意図的に行われたした。なぜなら、ハッシュセットの順序が定矩されおいないずき、および癜黒のドキュメントが「それの䞊に眮かないで」ず曞いたずきに、あたりにも倚くの人がハッシュセットの順序を決めたからです。 したがっお、開始しようずしたずきにJVMを再起動するだけで、これは機胜しなくなりたす。 あなたはそれを手に入れるこずができたせん。 危険はありたすが、このこずは偶然に機胜するず考える人もいたす。

Java Puzzler6ゞグ゜ヌパズル


Jigsawに関するいく぀かの声明がありたす。 どちらが正しいかを掚枬しおみおください。

A.ゞグ゜ヌパズルアプリケヌションをモゞュヌルにするず、 classpath䟝存関係が正しく読み蟌たれたす
B.䟝存関係の1぀がゞグ゜ヌモゞュヌルである堎合は、 module-infoファむルを登録しおmodule-info
C. module-infoファむルを登録した堎合、すべおの䟝存関係をclasspathずmodule-info 2回曞き蟌むclasspathありmodule-info
D.䜕も真実ではない

正解はCです。もちろん、すべおを2回凊方する必芁がありたす。 良いニュヌスは、 GradleずMavenがこれらのコンポヌネント正しいclasspathず正しいmodule-info の䞡方を生成するこずです。したがっお、ペンでこれを行う必芁はありたせん。 ただし、これらのツヌルを䜿甚しない堎合は、埮劙な違いはありたすが、2回実行する必芁がありたす。 module-pathフラグを䜿甚できたす。これには独自のパズル機胜がありたすが、次回はそれに぀いおです。

Java Puzzler7゚クスペンダブルズ2


The Expendablesのコレクションがあり、それらをすべお砎壊したいず考えおいたす。 このように砎棄したす。むテレヌタを取埗し、そのforEachRemainingメ゜ッドを呌び出したす。 そしお、各芁玠に察しおこのようなこずを行いたす。次のレコヌドがある堎合、移動しお砎棄したすこれはすべおforEachRemaining内にありforEachRemaining 。

 static void killThemAll(Collection<Hero> expendables) {  Iterator<Hero> heroes = expendables.iterator();  heroes.forEachRemaining(e -> {           if (heroes.hasNext()) {                heroes.next();                heroes.remove();       }  });  System.out.println(expendables); } 

オプションは䜕ですか

A.みんな死んだ
B.偶数人だけが死んだ
C.党員が生き残った
D.奇数のみが死亡した
E.すべおの答えは正しいです。

正解はEです。これは未定矩の動䜜です。 ここで、異なるコレクションを送信するこずができたす。これを実行しようずするず、異なる結果が埗られたす。

ここでArrayListを指定するず、党員が死亡しおいるこずがわかりたす。

 killThemAll(new ArrayList<String>(Arrays.asList("N","S","W","S","L","S","L","V"))); []< /source>     <code>LinkedList</code>,   ,    <source lang="java">killThemAll(new LinkedList<String>(Arrays.asList("N","S","W","S","L","S","L","V"))); [S,S,S,V] 

ここでArrayDequeを提䟛する堎合、党員が生存し、䟋倖はありたせん。

 killThemAll(new ArrayDeque<String>(Arrays.asList("N","S","W","S","L","S","L","V"))); [N,S,W,S,L,S,L,V] 

そしお、ここでTreeSetするず、反察に、奇劙なものが死にたす。

 killThemAll(new TreeSet<String>(Arrays.asList("N","S","W","S","L","S","L","V"))); [N,W,L,L] 

したがっお、決しお 絶察にしないでください 実際、それは偶然に起こりたした-誰かがそれをするだろうず誰も考えなかったからです。 これをOracleに報告したずき、圌らは䜕をしたしたか そうです、ドキュメントにそれに぀いお曞くこずで「この問題を修正したした」



Java Puzzler8埮劙な違い


オリゞナルの本物のアディダスを、それが本圓にアディダスであるこずを怜蚌する述語の圢で䜜成したいず思いたす。 機胜的なむンタヌフェヌスを䜜成し、それを䜕らかのT型でパラメヌタヌ化し、それに応じおLambdaの圢匏たたはmethodRefの圢匏でmethodRefたす。

 @FunctionalInterface public interface OriginalPredicate<T> {   boolean test(T t); } OriginalPredicate<Object> lambda = (Object obj) -> "adidas".equals(obj); OriginalPredicate<Object> methodRef = "adidas"::equals; 

質問これはすべおコンパむルされおいたすか

A.䞡方がコンパむルされたす
B. Lambdaコンパむル、メ゜ッドリファレンス-いいえ
C.メ゜ッド参照はコンパむルされたすが、ラムダはコンパむルされたせん
D.機胜的むンタヌフェヌスではありたせん

正解はAです。パズルはほずんどありたせん。 しかし、䞭囜補の機胜的なむンタヌフェヌスを䜜りたしょう。

 @FunctionalInterface public interface CopyCatPredicate {  <T> boolean test(T t); } CopyCatPredicate lambda = (Object obj) -> "adadas".equals(obj); CopyCatPredicate methodRef = "adadas"::equals; 

前のコヌドずの違いは䜕ですか アダダに加えお、むンタヌフェむス自䜓からメ゜ッドにゞェネリックを転送し、ゞェネリッククラスではなくゞェネリックメ゜ッドを取埗したした。 ゞェネリックメ゜ッドを䜿甚しお機胜的なむンタヌフェむスを䜜成できたすか

A.䞡方がコンパむルされたす
B. Lambdaコンパむル、メ゜ッドリファレンス-いいえ
C.メ゜ッド参照はコンパむルされたすが、ラムダはコンパむルされたせん
D.機胜的むンタヌフェヌスではありたせん

正解はSです。メ゜ッドの方が優れおいるず譊告されたした。 Lambdaはゞェネリックメ゜ッドを実装できたせん。 Lambdaでは、パラメヌタヌを枡し、それに型を指定する必芁がありたす。 衚瀺しない堎合でも、䜕らかの方法で衚瀺する必芁がありたすが、衚瀺するには、ゞェネリック倉数が必芁です。 ぀たり、そこでは汎甚のラムダを䜜成する必芁がありたす。山括匧内のどこかにTを曞き蟌むかTを曞き蟌たないでください別の文字を䜿甚できたす。 しかし、そのような構文はありたせん。圌らはそれを思い付かず、それから、倧䞈倫ですが、ラムダでは機胜しないず決めたした。

 @FunctionalInterface public interface CopyCatPredicate {  <T> boolean test(T t); } CopyCatPredicate lambda = (Object obj) -> "adadas".equals(obj); 

たた、メ゜ッド参照を䜿甚すれば、すべお問題ありたせん。そのような問題はありたせん。 したがっお、䜕かがうたくいかない堎合は、ドキュメントを远加する必芁がありたす。



Javaパズル番号9参加する䌚議は


䌚議に行きたい、倚くの䌚議がありたす。 それらをフィルタリングし、それらをTreeSetに入れ、それに応じお結果を印刷したす。

 List<String> list = Stream.of("Joker", "DotNext", "HolyJS", "HolyJS", "DotNext", "Joker").sequential()            .filter(new TreeSet<>()::add).collect(Collectors.toList()); System.out.println(list); 


あなたは䜕を埗たすか

A.゜ヌトおよびフィルタヌ凊理[DotNext、HolyJS、Joker]
B.圓初の内容[Joker、DotNext、HolyJS、HolyJS、DotNext、Joker]
C.初期だがフィルタヌ枈み[Joker、DotNext、HolyJS]
D.゜ヌトされおいるがフィルタリングされおいない[DotNext、DotNext、HolyJS、HolyJS、Joker、Joker]

正解はCです。これはreferenceメ゜ッドであり、1぀のTreeSetがあるため、フィルタリングは機胜したす。 初心者は、 referenceメ゜ッドずLambdaメ゜ッドはほずんど同じものだず思いたすが、たったく同じものではありたせん。 LambdaをTreeSetた堎合、新しいTreeSetが毎回䜜成されたす。これは参照メ゜ッドであるため、このフィルタリングをすべお行う前に䞀床䜜成され、参照メ゜ッドがアタッチされたす。 結果ずしおTreeSetにあるものを䜿甚しないため、䜕も゜ヌトされたせん。trueたたはfalseのいずれかを返すフィルタヌずしおaddメ゜ッドを䜿甚するだけです重耇を砎棄する必芁があるかどうか。 実際、あなたはたったく別個に曞くこずができ、それは同じです。 その埌、このトリセットの結果はGarbageCollector 、䜕がそこにあるかは誰にもわかりたせん。



結論


Javaの性胜は向䞊しおおり、足を螏み入れる方法も増えおいたす。 したがっお、ここにいく぀かのヒントがありたす。


パズルに出くわした堎合は、puzzlers @ jfrog.comに送信しおください。次のカンファレンスのいずれかで3シヌズン目を過ごすこずができたす。 貎重なコピヌず匕き換えに、ブランドTシャツをお送りしたす。



私たちず同じようにJava開発のすべおの詳现を楜しみたい堎合は、おそらく4月のJPoint 2018カンファレンスでこれらのレポヌトに興味があるでしょう。

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


All Articles