From 1d8224ceab21b3c0a717c1f545bd7542c657c388 Mon Sep 17 00:00:00 2001 From: Oldcauldron <48331519+Oldcauldron@users.noreply.github.com> Date: Tue, 20 Apr 2021 10:06:37 +0300 Subject: [PATCH 01/58] Update concurrency.md --- concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concurrency.md b/concurrency.md index 4dcd0d0..0f4042f 100644 --- a/concurrency.md +++ b/concurrency.md @@ -769,7 +769,7 @@ public class Singleton { [к оглавлению](#Многопоточность) ## Чем полезны неизменяемые объекты? -Неизменяемость (immutability) помогает облегчить написание многопоточного кода. Неизменяемый объект может быть использован без какой-либо синхронизации. К сожалению, в Java нет аннотации `@Immutable`, которая делает объект неизменяемым, для этого разработчикам нужно самим создавать класс с необходимыми характеристиками. Для этого необходимо следовать некоторым общим принципам: инициализация всех полей только конструкторе, отсутствие методов `setX()` вносящих изменения в поля класса, отсутствие утечек ссылки, организация отдельного хранилища копий изменяемых объектов и т.д. +Неизменяемость (immutability) помогает облегчить написание многопоточного кода. Неизменяемый объект может быть использован без какой-либо синхронизации. К сожалению, в Java нет аннотации `@Immutable`, которая делает объект неизменяемым, для этого разработчикам нужно самим создавать класс с необходимыми характеристиками. Для этого необходимо следовать некоторым общим принципам: инициализация всех полей только в конструкторе, отсутствие методов `setX()` вносящих изменения в поля класса, отсутствие утечек ссылки, организация отдельного хранилища копий изменяемых объектов и т.д. [к оглавлению](#Многопоточность) From 333bf78e43cc8858c0b70b69914f8f7c3c41e545 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:14:15 +0300 Subject: [PATCH 02/58] Create Placeholder.txt --- images/Placeholder.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 images/Placeholder.txt diff --git a/images/Placeholder.txt b/images/Placeholder.txt new file mode 100644 index 0000000..a4aeeef --- /dev/null +++ b/images/Placeholder.txt @@ -0,0 +1 @@ +Images folder From bbe4b08b5c715919aeb32b973ffb4375ab145022 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:15:25 +0300 Subject: [PATCH 03/58] Create Placeholder.txt --- images/SQL/Placeholder.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 images/SQL/Placeholder.txt diff --git a/images/SQL/Placeholder.txt b/images/SQL/Placeholder.txt new file mode 100644 index 0000000..a9b4ab1 --- /dev/null +++ b/images/SQL/Placeholder.txt @@ -0,0 +1 @@ +Images for SQL From 70325cc348e27cc3920681f76659533417f289f5 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:15:42 +0300 Subject: [PATCH 04/58] Add files via upload --- images/SQL/image.png | Bin 0 -> 6808 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/image.png diff --git a/images/SQL/image.png b/images/SQL/image.png new file mode 100644 index 0000000000000000000000000000000000000000..0e152e53843779194b1e2f0d42adebadbaa792ba GIT binary patch literal 6808 zcmd6sXu#*fh0G?qb8B?m1#~L4sU&mD70ZP(3zyVH#2hL$7t~5~ z11BqUH_0tUvn){*R9v&b4Z#&~;r!0`_xm3bF5211 z{o~L-cI?<8ch>gwCE%3_JU)HD3wXYC*ePbmjzjRXr>z|C?3~Z@EZ3<`z7O6AUezHx zSU=kNE%}^`73`gyne-6lP3yDYi%E%QW|n>l8;Ota=w4+WZkB{&-tJpvLpMYtBI<5D zN~U>;vL+ma(<1zX81Ld3JDTTdyy$DA>;qp!-_ev;N0=K+Ingn05C=4$4c`zC8dH!C zQEXG^`K~)ew8a}D`utUmQn96h%f;$iB06j2>$}1knXaU!03<@BU)vB1>zB<|itcB0 z=rQ%0B|K&L)UzWXioqJaqo=oPKq&`xy^aJN@w#r;x`?v^x<8LT`gkV8s>U|mT6f|ga( z7gaQI;#=U+m657Vdo#QsH@_HHRN)iseJxjGbx5C0u-U{H8iXU5{Hbo@XQzt#XQ2Yi zc7$R1jJIr2!rW^_bFUB0yDx`5!E%;nz|J9FbJpvh49<4w5sdnj@6CkSrZED=*HsJ? zWJwCBixcPD1`{2?O%Eq2-U7?$#{N+o+RIbBNFdayjq4V{hl9x)2Zh!QwM*=WTHzAK z_OiE~B5lI?1oc0ziq|_&WM<9_VUM$^5xdl)v>#?SMm790L_7s zM%>D&WkW+@2aVb%<1T> z`)$G#B`QB;vAkh-7?rPuxXs>69oTS05-p-7t`KP21r`k4O+<@iZ)fO1OM3AHw~rs^J&T0}xh#D3(hr9ccD z))cWWK2AgfZ$zw#DyHz;!OEf`<=jk3`$`|uStC-Y2}hdtU|k}^YY+>CY&w0#8PV6A zsae8Shl`Z;Am}v3*WiR8yjxS@S>>}Odv!jQf;&iw$&?he$6c?5bb3jJnBy9aH)BrA zrHnd!K}C*PRHKi^6#t+RS-r#AoL66E^SWV3f5ivFsCY3!RW!7t&G7rO;#64N;F;+H z53Rr;%sOxQ?z5jc!#z=NJUGu9&4=seIAcTS=ja66!ls!xudvC$>B_Gk1CeEt#hvaD z7-v)>W;M8dqwGPECE4)L3_cvON346TkJ3LlH?A0h=zrQc3lNVGm^);9d6U@H6EJ$D zQgi?J>_I((+)=l9yeg@UP>1#i7sLnJEz?h3?J6gHS|w(-Uno~J0k$*B0)-lPR?meu zqkG2BB>G|<&8ue0L%3II7AJ)5x%2Advc)NJ#WfkK%?;#JDdR+yM)>2L?d3&XO9)LFHPQ-kw=;Y-=MbwRAb+;eXLMHh}%DE0Pyez&k)ZMZqCg_$tv+;w& z8qM6dc@H4iGNwxS6*dC%jXCZ0Rb&u^V!TlUC&W@P;2z~~H^)Il8|yZ@eV^%>9Pt48 zkui$S&k(AH_wgr3gF2>jBwGx=Qhem-}ax1z5&rSACEBHN93p3 z_*6#biLPqch0TDb4V`HbsDfj*kgXnGHE7tLINv^Wg)R!0@uTPC2u*kYl+KU-6KwjU z9&G3C;Zy^WqPvvih6$Lkpyz~81_~B-zXw)Gbj&~gy7o~gHjVU|19r18BiwK?HLzhe zP;F^5ag6Smskpp@zI(u&P=RF8xKl92Ka8E^>x%)APP3xYPaZ9piW2_ke$WpUtj{C~ zN--R(>fzzpv=*%xB(fctJlHq2(aXB|(B}MMkM08_#mS($Lxx;g$GLXEPt<2Ron=~+ znl+|Cok>8BokxN(WoBAoL3l674a;UtTWiy5BLu&e_zb#nOQOEf;s>v$NS@}2YXfH@ z{AxX1q^qgtW>=_0lKr`QVL(~$2Vfd5V zvX5QG-y3GJeTy*0@XePV%k$sr$(I7SE6l{j#ICn8)na{buaMqyT8_6Z)O4!2blr`_ zmNll8u|U)MBvE+45J1l|5jl5#AG3?6o@@e7$DqxL7bjH*F-Q9}+2vHTiJ+hH&! zgj|rxdkoEte!}$s7*|2X5kD`sP4%Fcdg?ON*1q?T($JK=!ZrO|a+9S*J(odKh)}e* zwHDoe3W%mal<%;SM~j#uC+#+!opT)Q^^qmP&c(3h^+{|eW}vNlj!Jo~`^DDkMcR=&uO%?t)~SFYXk_4+w+v)TR49HGbFo=}Xocb?QO|1A#1ZH* z;7cy`ZurBos)(5cuM=Bz`ZE5B?8hCtx}_gv+kt7+cvT+i$4!{o=@3i_+|JR)*f8Wf z4F5$2*S-0ONN%Z2+|c(mGG$w|o<`anEJfaeQub8Q%mk(fy4RvON#1#Oa=-ZPv6b7!Z3=x~IE~Gs zJE~2GHfln{Q$8z`mTwmiD&@PV@~>?=Z5jg|U3Y1O!g0~at#yN_;_+d3I97pVZy0x; zp&+_I_Or?5l*E-?=H7t3JcTRe(2mh0Ndjxt)mSf_{B8+8B@-TF&H;AyN{?@O>molvIh) zO88B`WBAb189`uVs#S;vmSZJQBdLlmn3&n1-l(Av)qd!wapGq=E$5LCsEXy>Unu;2 z=7;grJ~L@)m^-51Ra@T{;#*nRCXa$n8jn3Rb%T=dP8En`dlDYO{`Ipv?$Hdw)brzq z$P$*%U1`XL0oZ!??7MCy-Up?|4y!N9sg#tuYw#Ji@Yrme9wvV<=e$ad;?wC1H)>bG zEm|{jR7!^4iSWT)?F~zs3(fn6{*nl&@=uTDl(J2zAw=Qmv~o?|k)ql?+k|qrXsP=_ z*L=D7dKmyH8m}K6daAU3?$7)qR6t;%0isS38nKHlR~jX=+@Mp9W{Q6%Bjb_%%ohvP z&`qY%c=J_PtUw;&qn8F8wvHpgqNpF^KkrEU7VHassPJm+7T(dI3QGMhIoVog-A zj+ZxXVt*Ze;32x-=ujN=RXqbk?d(BSGFJ7$q$~Tg7@V_dQa7_em^#2s?!W%XIFN3i z+@Rq7t9;DKae>iDo~iS+0X?T#0VVS~YKwxdO_RR$2Tv+3|HD|<{D{MAy;)6q&T?7w z%rLsKG+2waX*U|3wdwh+KYSk#DwKZwE>B!+Cv-k{v+tAaoM>$0Sfhar4Vrxxxxe$_ z<*o#v$N_`HaaoLCt!JnI%Qb$k&bByO{Q!ESi{a|Cxbw9-7EG#*0v7d(f6Avp)P#ey z3E_)teTDzqlym3Hp1|s>=lU)u10fay>oA^}FVH_)U;?L8_TMmD@4oIe-iITKC*tHm z{WloKxdx#Ei)s+KWV5Ep0)<~qwG!mhdiWohLC=i|+}{Vxfax%9i2`lS9Kj_zB?!)H zlpuW4SUnT`J^`X*P0N-6zp8Oo!Hhm>uC1K}B5Sr6o8?T}+=w~^%~_V~v(zNswXOlz zunbwHqsCjfB!PH2LAO&rd9KlkpS!Vwq}`itedVQbBHzR9Z3e7ls#G2TuZ@hg7|?Z6 zwlK`yqdOKKp%*t}ightPLM7DrO>x$iRLYQ$K$7d5xk;BCS{&>gEVm8V$#Z$AGL?c& z5HPQe?TxWbX;oo1+j#>u^p-HCV&__V(C~<%(W-(6qZhgooWa#G<{ehhU2FL#{M@Fk z6Ig4Xi6W0Hx@)0|P?w^uyth&x!K?n=V|nm2O_w3s4n8xO@ zFK=C_0sU5}S~n-olT>53M9PG7L(SzfNuEAzxS>VF3v*~T`{nXr=eE`3rH^pU|9BqL z%UfyuNV7ynJqEYtGwPV_rx26=#oyFJV(Jw}*1Rh#~33YoVR2P-q(@7vr?O}e@; zppyInlw?Bc%E+2HLCq5R0_Lnw5~0Y4s~fjyGtC2^(eH?g@Gb~m#qKSv1qu+@Vn?Uu z#3NSrbl2diT}3QE0pOA&It00Hg}r$*PK7AtH=hq$K)h)R8^Gd6f1EBx&VOCObrp#1 z;n5~O${)`on|A5jUf9Z!Tl!!5sr`6`d}+kM9kk_tM=2Ukevqq!H?XyvR1;s8IKs;J zb_%TJO4{S>Zv0ELzXI|B;NjyTAl~*JlFr>g4NEQ*g3P+kU1*opI2b&!K zas93!cK5O%V2~(+w@-F@zcePqi4TWw$6r9T7tKy@sdn)%)v5+R)8kGE$%mz6HPTmK zw42dwS0Igs+Jjmbwx;Z^Ly*TAkawiD*n@-faW!8pgYQ9l1+>w9 zB)=Kz>Sjz&x+|B0d~i`~f4YvcSxm5wF2^#FwL6_Q(wze`>feh~9mzRqV1p_Et*$jW zemZb8?g#>8gPA*l%SE6HYIvZc=)nU(X%LZVc}zZCi8(yW`q@zWW{1m^TD$NxQbWjHeJ|2x=1nUmj#VZ0*!65v^+kDI&Av>}hD4*a zZ6vPQ)%J!AyBi8^4E{G}H8wGu-2Q*ZEWGl>CT6`@ed6!|knhEtsHUnCWOb;23P~Cz zX6&{Gj+d&$fyhtipp*)IcHmbf=oTKlPi-dtdVxlPVlf6Pn)8`de9 zX5cwH0k7dE{CP_MkY!2vj6j7oJPZUo!jpEd!R$w3PCZZ+XU>;7tUzsafsHMezZGvZPKhT}BIJ7t`xL5j2^k7{QITI6PG6VhVFWz+2!oNx9A zFWXY_jFB|0ak9#~MXGzWk4#q^)yoi_^9MDc_k*Ot6oiZ)Cx6ByCz)Gx zZq?CC*Sxq*8)d6)u=4^e2^!_PPTq3%WHlU~(MIb4te{Erhg13iHBRubTr0{)rMYQG zQ1G3Go3~TS>fiXsf)0vKY6#C5V}UpzRg2s1Bu%3rKJc;DyOb(3dt814O1IKze`>~$ z(2HSxz}XCXk%TQEU5{ox7n@sHUmf+phz@4UrNd-f?pg(=omWeJS_~u>$-2d&5as_3 zsyU-se8;?|;puc&$cMo}?lhOz-r53eG5wDVVoTmFNx~ZU+i<+kRy5?w1|H8O`IKy@ zK2`Yh*#t`Xj85w|y!OLR-ui=*LJDx(c6CGMmpwOhqmI9d4+VPXxi{hW=&HY-$t>z#j~gObA=H0ldo$o>DF#FB+b^R%Ay%YGcSOL*x9zqpN z-8hWx+dd`%&IvAAUv7S~sqR3z^M5Pt4kE?u0Cm6|ks5h;rMqps5EYUP7-7KW3uUuH zhS7VU)=h^gJmc~x?)ktX+xbF&@Gii7Uzt(;C-{aX?Zc+MdSvZ4aH5}J^-R;G6C7~F z<(DFq5QR$i4Bj*#=*#v|s|Ry_f+s*}V6q|>pnOwv|Mt&DdQJtb46n9!V(WmQ$_xMV zkL|}{z%OKiot$Y0gM$^9s47`9woIU)!m0iWrRL+#sI_RKl#6284gf(9asOs2IwJn` zFR4jri#W!|Wx=Gg`TE^e$B*Wr&t38oryczv`Jde}S-Gpe!7q(hPi$;Eh#qryLdj)Y zFOh1LMJ%k-K2yh^I3P}74CqVeS2pgavMeaIs4BhAl~x%R?8im-o6w#SI_VwYoAgH* zD~#^ica9kjueNFnofvuUIkI0fZrGw=8+DTPW{6DYI_jD6_y7HvW=d|+d@4i~WO3(M z(6P$!Z^n36ELLYXHhjhm5)Bgjk$0a+*Yy_4>@d7M*(iqPhMeTOXpeMxC1$(F;^Mbb qK}>&026yZ_L4f#1KXyar;gZoWQFgbzfPb8JoIPWAy8JiqKmG&y(YR>< literal 0 HcmV?d00001 From 9d03ba09788487ebc93e0035bfa2d8e4a1c5dbe8 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:20:44 +0300 Subject: [PATCH 05/58] Add files via upload --- images/SQL/image.png | Bin 6808 -> 11194 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/SQL/image.png b/images/SQL/image.png index 0e152e53843779194b1e2f0d42adebadbaa792ba..8e4af8f0fb809c84e9bb886779549c66d64bc19f 100644 GIT binary patch literal 11194 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 literal 6808 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 From 73cf862150c91093159ef5220a87eb0a938b9dc0 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:21:33 +0300 Subject: [PATCH 06/58] Add files via upload --- images/SQL/row_number-sql-rank-function.png | Bin 0 -> 6245 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/row_number-sql-rank-function.png diff --git a/images/SQL/row_number-sql-rank-function.png b/images/SQL/row_number-sql-rank-function.png new file mode 100644 index 0000000000000000000000000000000000000000..305c8184f3553f987cdbd0ea322cbcfa73fd74e9 GIT binary patch literal 6245 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 Date: Mon, 19 Apr 2021 19:25:18 +0300 Subject: [PATCH 07/58] Add files via upload --- images/SQL/row_number-example.png | Bin 0 -> 4544 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/row_number-example.png diff --git a/images/SQL/row_number-example.png b/images/SQL/row_number-example.png new file mode 100644 index 0000000000000000000000000000000000000000..ab3f1b9746ae7f5ff3243e2d979b5132f5289c5f GIT binary patch literal 4544 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 Date: Mon, 19 Apr 2021 19:27:20 +0300 Subject: [PATCH 08/58] Add files via upload --- images/SQL/ranksql-rank-function.png | Bin 0 -> 7198 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/ranksql-rank-function.png diff --git a/images/SQL/ranksql-rank-function.png b/images/SQL/ranksql-rank-function.png new file mode 100644 index 0000000000000000000000000000000000000000..f4236b326039bc87162078b1d285e4b5284dcb63 GIT binary patch literal 7198 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 CC Date: Mon, 19 Apr 2021 19:28:52 +0300 Subject: [PATCH 09/58] Add files via upload --- ...utput-of-rank-function-for-similar-values.png | Bin 0 -> 4840 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/output-of-rank-function-for-similar-values.png diff --git a/images/SQL/output-of-rank-function-for-similar-values.png b/images/SQL/output-of-rank-function-for-similar-values.png new file mode 100644 index 0000000000000000000000000000000000000000..4584ad874f69e9f06ae3b0565b9aa7e2ad814b93 GIT binary patch literal 4840 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 literal 0 HcmV?d00001 From 2057860e61904bc3439d4e1f799bd990f5c556d5 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:30:26 +0300 Subject: [PATCH 10/58] Add files via upload --- images/SQL/dense_ranksql-rank-function.png | Bin 0 -> 5858 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/dense_ranksql-rank-function.png diff --git a/images/SQL/dense_ranksql-rank-function.png b/images/SQL/dense_ranksql-rank-function.png new file mode 100644 index 0000000000000000000000000000000000000000..555b185f2516c66e2618eef450dfb499ccb54c85 GIT binary patch literal 5858 zcmZ8_2Ut^Evvw#_6hXj77Yxz_1f@5XAOr{+Y0}XUlp3T;=YS#|3B4;KohZEoDT2}s zy#_)@N)UsTQ16cZ=lkz>^E@j%nKgT@y=K2N^Uj1n(9=A7n)5UW1Ud`Vf;=;!G!(n#{^B3{Y=5otVfzvJQl z4CM+c#PnzZA|`i01VOqXT7<%FVs=Fj4GZV1Q6fT}B~rnxc}5HnE3 z#*bZ{?VO*2nz@!<12X!*_j|Y^kf808khOo+)KN}ONN0D@PES%3AfuzG8Q8fyB0&Wk z141Csg;FTwj=_rz;*`}hp3%(aU)hd=Nrb~IQ{t(A&g7PyrB z1pjbKF0y_oK>O%{3sl?kG)cX{O!(0`{7#EtFkPCeMxG?qPqs)W*|N-Y-lMR@Z!4Ck zu!i;JRV?2>D{;5W4(TQ@`QS+ z9&V~noW0SfNgd-g|LyE3Kd3;8?FLAGfbVc|;DZik4it26yxL!@x|W$5l=fq6G}dv0 z$}3a;dCux12xK9IMfFX8KV0Yl6QWp?9oxR7-=q3<6+5Fvqhbwmc}dFzig}S3bg;kg za}qITG&ojmh4-15z!bKWCc^IbKVmCvZk1 z?c@nhBxB7f;-IqSc2I~se5=sx;FWLCZ-!YK6uZl#-BZcG??z$qk*2(OOT6shNce=U zOX|vem+hpj$>c42D?@D`y_}I~AIC&TT=%A8A1<9gEIK+GCS+7gpFHwDvYs~9j8~?T z^>EzgsMZ5rZLx6U&Lh(UK@|y!tXe|+h*|H*ofdYe6%%R9eGxzR_;Rb{ zG}tnNOv*lD~a;17U1)mI^xwg?($-^bHg0%5xwc*L{#S(KpwYj`v_kAZw z(!S50PgeWup}!Z3EHG|!0xq^2CH+|Hh&$ADAWf}i(2Ul?YnS5UV#9WR z0Rbh?^*4=;sw?h_1NK#WYON=jENnS(tgID_*b=e5hVVk@!@qCn5;3ArN-&tN34g^! zljwEM65`(a>S__w*|T-btr3z^2W(F*Xtzr09p%a$`aBq>SKSpc>LBYo7SxvHJ@!%l z7sbQ&b<9*jr#u)_cwIby2T?WI0QQ`A$Qq&fp7z#>Z`6X2FZWW^x4C6Sd2pl~=Thr79pw+9P# znyWi&umPLPF0L?BUcEgi3Y5222Uz1_e1;R_wZZTfnD&x^)CIxht#;)zV+qS-l(Z8n(%;=A@UgcnmZ%-5!8(xvP)lQgm#=HqgXMC1Y7Et+*8XYEAioA)ns2s9JmaN?kf?<-=XETo z^XM~pyuMHcz>|YksGhbvJ`1ukNCdOR;kwqCiiCg8ubp@->Ud{g;X~Z>5McjQOaf00 z2+!UhBNNt7^z!v52c%V#dVdMpPJ{7qIa(?Z>_1=&^PnDiFd=wZ-C!kk<^(!<+cNPe+{iXEQBTp!9=0w<#;|Ad8qAf7U(jL<+B5} zn48;~{c4h1p9I$SaqG7%>c}5GAA!gWTJy|F+1XruiH6ko+4dr3=+@W5?>-4L&PPL@ zSAJ!0^B#9h^=ZCin5_(#+!T<=ObV9!3N|hFzDYEx_$DP-S%kzux^nT#E z$eP`*?+ue-uXxv@4e$I1Ok*PqU5MOR6jq7obv!(9w>Dq#@MFC9kiTXJ4_KPsGe`{X^t3G9~9-U(D+A$?_9} zf^(E)6N-}%&3-vd&Gc2e&0tHAYC&)GWzY=Q1(g{wKQ^WpD>sbO>k7o6v>@2KB5?mZ zz4k~p2~+YzYN0cHvAxMD6>Xh{4pNtC{$Ge=V7v_C?#u|Xm}@~II@RxK}3!*wKYKtOb=Y>*AV0rJ` z)En~Bdh6-A8y6N9e%()X`&F+hWd2j_jHNyWZ+PO=-VL&XV0h1Y8CkB3kknt6ZmOU2 z9wN&T2&T9;tW-h*?O-V;f+{vS%0 zD+&-y##LblzN|P6_E(cEy>Si8YD0sJ%#C;haUn8jg&AciN*2O5tN#!$E z*<80`4XH;wAGRm9lo6pR7^`Gn?IgL3nf<)AJmRGWlUtd)74Kg88suq!TPL;RkysA{ zgK}Z9mA#ZcVd#*#5#JX(9Yth9OTTB7MukFSrAK7_K!I<%&^s`^!i43{v;9r*YDjjj z4fh4?iq!C;Iy!eA<`CIH*}g$|;=9?~ZtPF0^n^Mo3)}L5hn+lDNT)OLP3a}s7u9(a zz`^(Tc>ncQ1OGE~rp1ejw4eee3U`8NKy%bH^*$WXd`e|WR9e+CgbG+`*FH1+>;B=X zXvqIHdgfoEWv+$ot!1t`lU!IpzFb-DHbmwyUn1e7a}=uI*2MB9`vxAqU%O%7UVklP zMB#Z=8~kZn)=y#Ra{f}SO#8_8t`{LO@MIv_#>V#Ex9mVmUOo;HCo8Xu7Z*0F90UZ) zxBB=wva&9+#(kg52@9*t%aeAJ+uLiH6xGJ?Gw|tgD~sa02PW3KBDX5!CwDgzqqjZC zTap3%#w^@#%p@DGu#AkHCg3t(o$_A$0k5m61n(v#EfDA1eLHI_YR7akOlbMCz05S= z9zy24dBdF6-}3D54JpndF?LyJVQ!8Vz?#IPhUt|K5=)?P;4vAuct)~O7~8a6`eny$ zcR~huxFpF&Qbbr-Ne{03yZUPgI1n}Lfs%{Zm6^4cln?heSCLLH*K5hPX!<1xtKu-% z9IPu=sKyWvcGb$)2PbP5Gf{zN8-&kd?}hGPEYB9Fp&_-kL4NMWrKWal*MA<}*2^DN zcZR{B4))r|`x6eNPA*hfSjWsluHQ!L)2JOD?)`J#@`wE=q{(fMyr6M zHO=FTymw#x>`9$=c@@?%K`K{%WEQ_h^h7bt`(UTIM4_CXk5aP-nf3fW82eruo?ov)J&F3 zt4U(B{AE3}y@z*vo2S6H1qzHfkU69QHqGPaoL(kHsW@N;+JIbTSfO0tb8u=Mz4JO`X zkTZ$BG|>;@s(t7%uIPC-d5 zBtD)rw(0WjVB)5n&{}4UIjZJE)36ViH9}bzbFEvqO+}(Xd2MHYfs@9QzxJfyNod-A z>$AE#JCLg9E}tuNGSMSL34T5Y)%c7|aYsIf?(WaoSe3pR zdIYkL?I00k0a^i1$yf_t4a8xJ|B(j_%B=Q>dGE-VGH1{vfBP0ek`XbqD$p z9i)9oxfB#kF5|kh>guT92Mkfnh|%kdq0=vRl>FOiUfg1V4S%y>Xn)=fSwr$!f~397_JC5Ltp2tB1bEM0sxe z&!!h}Pi|%5wd@P8#}sdYeV3MG{fA4UxD@tfsi(f`Buj*cb%e7EohHOFT3!1zQuLj; zOi2uG)AA=}Kn2AAQ!^rZs(~OA=YL6}BQRi|i-O;Q zw6r3d^=f8-7G3plR{N8qBVWY7AdN|R1B3j7gak~}-7;z=d8K^6c(LXR$N)unb*9|O zQCBfCl9Zop>BIOIuJ|C^!5fehC41Um7^|j z7XttTiSVED&?+(!v=(2~M?bkC4qNC}*+YKvKlZaP&fU7}(8kB7F-hg)EKj$HO|RF(BLhwrr_7yYOQ_WO_W{oG1AiWAZ5%yYP@YE zQwce@nEc^mlhyHByV~@vPQA2ut*?=Xcm)nMFTKXSF0sVk2&1YA+$q+KR@p*oNPNo3 zl?pqtc)0~-Ls?z&11s^K_7vDzJ-sdfjwFH_IUI15M9C(yZ5|QQ+v;G}T8fS7eDDp3 z{v4P2By-mvu&wdBOzFLGK{0hk>|ZfzrLQmewzq}r?lW!_F!S2zX^7rzXsDLK*UQY+ z3r3(Dyq2O$#3hrn{4_ZGXfD3HXYvN7lw0aBnU^Q?dO-NNuCDNt&1ER%@pRUs_|Pk8?U~%f_A>EoeUI?B zMZ3ndy=8TtC_Cs#QZjP10_U8TBwZM4=B3z)+4Pz6sGs~%?@LU>@At?05FTS90G{U( z4E}2UP+I5^8;U4GLl3@+>l|P^_wA$>;M>O$Zxv*XLz(%K0*_l*7JwiC_^-{!^AC-) zIGtyal>8SMaN?`5x4%}7w7&9m!PEXg<`yVmQu@Xfz|{mCzF#nDb!u-3DL+sm#O>m; z66qZrMq+Uxv`n{4XIJdJKUH4~^e0wLmrL8%MrSFD+z;4FC++;2FGQ|KE=*m%5o9|K z#6J|DngoEfap@ZmOwZP|bVA3yW`im32dB21!K9~m@x}Rmz+ns+18HW%!x_nkZn#cL zwvm$J7a-f$3J!<*0^ybUaMhR+^zZBHCRiriEWd`2yQ--@B?7YWE5O4q70S#4EIKj=~5nY*n{@z5H9{9eC{mLKgR(qiu*4!#=R>wGBnLG%yX zXLH%pSf10kT!kw@0`*?jw_L8J$)T6`w;Y{gBpNcFQVGQm zCA5fMH6%G5UV3(Deh!Wjg}vDcO~{88+Nod{TTUva#FcsZPe7fDxyN(|=%M}R z_!N#D*TFJt{{0PZ{gC{(e52IG|2x!q$Gf}+dM|$)Xn$Ds8tuA|<#5SCmA^UO?@ObY zeIso&kxf~yb-7?|OE#Rc(Zqet@VUKBzx3}Ld5iM5+CxcFwEedez|`)W0je_vsWo%9 zjpY`+H6JUtSFaS7=1fR9nHZ-1=57hB%X{xGjya5mnQ*4-G}oJp%9erSjC2#n9Vs)J zQS)7dgzbOOYxAWKGqu_5zFl^y@K&RZ8(Hg0)B3V%R3CK3_NiJfP|3D13?VUj^8o z>LUSMl=>G<>OHCk!~!ux!En%9=;dJ0-)_{OQtglCf0_9Im%)^l)qg92U1ckQoMp&E w54y!n;o3I(EH5T^_!V}xuVS811>Ga7IZrVJ>vOPj0 Date: Mon, 19 Apr 2021 19:33:35 +0300 Subject: [PATCH 11/58] Add files via upload --- images/SQL/output-of-dense_rank-function.png | Bin 0 -> 3872 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/output-of-dense_rank-function.png diff --git a/images/SQL/output-of-dense_rank-function.png b/images/SQL/output-of-dense_rank-function.png new file mode 100644 index 0000000000000000000000000000000000000000..2f5471a81b636212456829e32b806d597c746a3f GIT binary patch literal 3872 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 literal 0 HcmV?d00001 From f9df3ff21ecb6c15f3f16ed8801d1b37e22cb00d Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:37:08 +0300 Subject: [PATCH 12/58] Add files via upload --- .../difference-between-rank-and-dense_rank.png | Bin 0 -> 11895 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/difference-between-rank-and-dense_rank.png diff --git a/images/SQL/difference-between-rank-and-dense_rank.png b/images/SQL/difference-between-rank-and-dense_rank.png new file mode 100644 index 0000000000000000000000000000000000000000..1f832c1b8b3814c65a4164223bfd79e811299408 GIT binary patch literal 11895 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 literal 0 HcmV?d00001 From a5515672524b1a9772e244a2d925481a1acb2f60 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:38:27 +0300 Subject: [PATCH 13/58] Add files via upload --- ...ence-between-rank-and-dense_rank-functio.png | Bin 0 -> 14414 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/difference-between-rank-and-dense_rank-functio.png diff --git a/images/SQL/difference-between-rank-and-dense_rank-functio.png b/images/SQL/difference-between-rank-and-dense_rank-functio.png new file mode 100644 index 0000000000000000000000000000000000000000..0838690793df52bde8e231a2d60daceeddffbf95 GIT binary patch literal 14414 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 Ief|D_0R_@BbpQYW literal 0 HcmV?d00001 From 95ed332fe9303730cbf717bdf4d07a04120d61f2 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:40:22 +0300 Subject: [PATCH 14/58] Add files via upload --- images/SQL/ntilen-sql-rank-function.png | Bin 0 -> 7288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/ntilen-sql-rank-function.png diff --git a/images/SQL/ntilen-sql-rank-function.png b/images/SQL/ntilen-sql-rank-function.png new file mode 100644 index 0000000000000000000000000000000000000000..0d25bf642a61d5a2a2f4d8d41ac82b07338fa3fd GIT binary patch literal 7288 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 literal 0 HcmV?d00001 From 7c4f5baf8ae7589eaa113bdce2c116eb14b10863 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:41:44 +0300 Subject: [PATCH 15/58] Add files via upload --- images/SQL/ntilen-function-with-partition.png | Bin 0 -> 7954 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/ntilen-function-with-partition.png diff --git a/images/SQL/ntilen-function-with-partition.png b/images/SQL/ntilen-function-with-partition.png new file mode 100644 index 0000000000000000000000000000000000000000..698216df7c197a5759dbd31f06156b6d5dd596b9 GIT binary patch literal 7954 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 IJTQOxKhhMs>;M1& literal 0 HcmV?d00001 From a07ab5cf405caa1d6796151ae9444675d36757d8 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:43:11 +0300 Subject: [PATCH 16/58] Add files via upload --- .../output-of-ntilen-function-with-partition.png | Bin 0 -> 6263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/SQL/output-of-ntilen-function-with-partition.png diff --git a/images/SQL/output-of-ntilen-function-with-partition.png b/images/SQL/output-of-ntilen-function-with-partition.png new file mode 100644 index 0000000000000000000000000000000000000000..03126b9cbda293e43df6b2ac56ca646e277962a6 GIT binary patch literal 6263 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 literal 0 HcmV?d00001 From 2ea948dca4d3d9a2c8f147338ad41e286f9af4cb Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Apr 2021 19:56:38 +0300 Subject: [PATCH 17/58] Update sql.md --- sql.md | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/sql.md b/sql.md index 4743f8f..6ec0ef8 100644 --- a/sql.md +++ b/sql.md @@ -333,14 +333,176 @@ __Курсор__ — это объект базы данных, который ## Расскажите об основных функциях ранжирования в Transact-SQL. Ранжирующие функции - это функции, которые возвращают значение для каждой записи группы в результирующем наборе данных. На практике они могут быть использованы, например, для простой нумерации списка, составления рейтинга или постраничной навигации. +К примеру, у нас имеется набор данных следующего вида: + +![ ](images/SQL/image.png) + `ROW_NUMBER` – функция нумерации в Transact-SQL, которая возвращает просто номер записи. +Например, запрос +```sql +SELECT Studentname, + Subject, + Marks, + ROW_NUMBER() OVER(ORDER BY Marks) RowNumber +FROM ExamResult; +``` +Вернёт набор данных следующего вида: + +![ ](images/SQL/row_number-sql-rank-function.png) + +А запрос вида +```sql +SELECT Studentname, + Subject, + Marks, + ROW_NUMBER() OVER(ORDER BY Marks desc) RowNumber +FROM ExamResult; +``` + +Вернёт набор + +![ ](images/SQL/row_number-example.png) + + `RANK` возвращает ранг каждой записи. В данном случае, в отличие от `ROW_NUMBER`, идет уже анализ значений и в случае нахождения одинаковых возвращает одинаковый ранг с пропуском следующего. +Например: + +```sql +SELECT Studentname, + Subject, + Marks, + RANK() OVER(PARTITION BY Studentname ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY Studentname, + Rank; +``` + +Результат: + +![ ](images/SQL/ranksql-rank-function.png) + +Ещё пример: + +```sql +SELECT Studentname, + Subject, + Marks, + RANK() OVER(ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY Rank; +``` + +Результат: + +![ ](images/SQL/output-of-rank-function-for-similar-values.png) + + `DENSE_RANK` так же возвращает ранг каждой записи, но в отличие от `RANK` в случае нахождения одинаковых значений возвращает ранг без пропуска следующего. +Например: + +```sql +SELECT Studentname, + Subject, + Marks, + DENSE_RANK() OVER(ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY Rank; +``` + +Результат: + +![ ](images/SQL/dense_ranksql-rank-function.png) + +Ещё пример: + +```sql +SELECT Studentname, + Subject, + Marks, + DENSE_RANK() OVER(PARTITION BY Subject ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY Studentname, + Rank; +``` + +Результат: + +![ ](images/SQL/output-of-dense_rank-function.png) + +Ну, и на последок, продемонстрируем разницу между `DENSE_RANK` и `RANK`: + +```sql +SELECT Studentname, + Subject, + Marks, + RANK() OVER(PARTITION BY StudentName ORDER BY Marks ) Rank +FROM ExamResult +ORDER BY Studentname, + Rank; +``` + + +```sql +SELECT Studentname, + Subject, + Marks, + DENSE_RANK() OVER(PARTITION BY StudentName ORDER BY Marks ) Rank +FROM ExamResult +ORDER BY Studentname, + Rank; +``` + +![ ](images/SQL/difference-between-rank-and-dense_rank.png) + +![ ](images/SQL/difference-between-rank-and-dense_rank-functio.png) + + `NTILE` – функция Transact-SQL, которая делит результирующий набор на группы по определенному столбцу. +Например: + +```sql +SELECT *, + NTILE(2) OVER( + ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY rank; +``` + +Результат: + +![ ](images/SQL/ntilen-sql-rank-function.png) + +Пример 2: + +```sql +SELECT *, + NTILE(3) OVER( + ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY rank; +``` + +Результат: + +![ ](images/SQL/ntilen-function-with-partition.png) + +Пример 3: + +```sql +SELECT *, + NTILE(2) OVER(PARTITION BY subject ORDER BY Marks DESC) Rank +FROM ExamResult +ORDER BY subject, rank; +``` + +Результат: + +![ ](images/SQL/output-of-ntilen-function-with-partition.png) + [к оглавлению](#sql) ## Для чего используются операторы `INTERSECT`, `EXCEPT` в Transact-SQL? @@ -396,3 +558,4 @@ GROUP BY download_count; + [Quizful](http://www.quizful.net/interview/sql) [Вопросы для собеседования](README.md) + From e3168994bf41264a61a9835b1f7db2d174f189e4 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 21 Apr 2021 12:49:13 +0300 Subject: [PATCH 18/58] Update db.md --- db.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/db.md b/db.md index 8311693..3f7aa80 100644 --- a/db.md +++ b/db.md @@ -261,7 +261,17 @@ __Долговечность (durability)__. Независимо от проб + __Потерянное обновление (lost update)__ — при одновременном изменении одного блока данных разными транзакциями одно из изменений теряется; + __«Грязное» чтение (dirty read)__ — чтение данных, добавленных или изменённых транзакцией, которая впоследствии не подтвердится (откатится); + __Неповторяющееся чтение (non-repeatable read)__ — при повторном чтении в рамках одной транзакции ранее прочитанные данные оказываются изменёнными; -+ __Фантомное чтение (phantom reads)__ — одна транзакция в ходе своего выполнения несколько раз выбирает множество записей по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет или удаляет записи или изменяет столбцы некоторых записей, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества записей. ++ __Фантомное чтение (phantom reads)__ — одна транзакция в ходе своего выполнения несколько раз выбирает множество записей по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет или удаляет записи или изменяет столбцы некоторых записей, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества записей. +Предположим, имеется две транзакции, открытые различными приложениями, в которых выполнены следующие SQL-операторы: + +| Транзакция 1 | Транзакция 2 | +|--------------|--------------| +| | SELECT SUM(f2) FROM tbl1; | +| INSERT INTO tbl1 (f1,f2) VALUES (15,20); | | +| COMMIT; | | +| | SELECT SUM(f2) FROM tbl1;| + +В транзакции 2 выполняется SQL-оператор, использующий все значения поля f2. Затем в транзакции 1 выполняется вставка новой строки, приводящая к тому, что повторное выполнение SQL-оператора в транзакции 2 выдаст другой результат. Такая ситуация называется чтением фантома (фантомным чтением). От неповторяющегося чтения оно отличается тем, что результат повторного обращения к данным изменился не из-за изменения/удаления самих этих данных, а из-за появления новых (фантомных) данных. [к оглавлению](#Базы-данных) From 70b5f9111cd86c6d8b6b94077ef0c15603bf0faa Mon Sep 17 00:00:00 2001 From: romiv <37421036+romiv@users.noreply.github.com> Date: Sun, 23 May 2021 17:37:50 +0300 Subject: [PATCH 19/58] Update jcf.md --- jcf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jcf.md b/jcf.md index ed364e2..197074b 100644 --- a/jcf.md +++ b/jcf.md @@ -99,8 +99,8 @@ _«Коллекция»_ - это структура данных, набор к Интерфейс `Collection` расширяют интерфейсы: -+ `List` (список) представляет собой коллекцию, в которой допустимы дублирующие значения. Элементы такой коллекции пронумерованы, начиная от нуля, к ним можно обратиться по индексу. Реализации: - + `ArrayList` - инкапсулирует в себе обычный массив, длина которого автоматически увеличивается при добавлении новых элементов. ++ `List` (список) представляет собой коллекцию, в которой допустимы дублирующие значения. Реализации: + + `ArrayList` - инкапсулирует в себе обычный массив, длина которого автоматически увеличивается при добавлении новых элементов. Элементы такой коллекции пронумерованы, начиная от нуля, к ним можно обратиться по индексу. + `LinkedList` (двунаправленный связный список) - состоит из узлов, каждый из которых содержит как собственно данные, так и две ссылки на следующий и предыдущий узел. + `Vector` — реализация динамического массива объектов, методы которой синхронизированы. + `Stack` — реализация стека LIFO (last-in-first-out). From 57da9ee9202d11d6991c7129a1ce2021188d1121 Mon Sep 17 00:00:00 2001 From: romiv <37421036+romiv@users.noreply.github.com> Date: Mon, 24 May 2021 22:54:48 +0300 Subject: [PATCH 20/58] Update java8.md --- java8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java8.md b/java8.md index d51fce4..ac2ea4e 100644 --- a/java8.md +++ b/java8.md @@ -487,7 +487,7 @@ optional.orElse("ops..."); // "hello" У стрима может быть сколько угодно вызовов промежуточных операций и последним вызов конечной операции. При этом все промежуточные операции выполняются лениво и пока не будет вызвана конечная операция никаких действий на самом деле не происходит (похоже на создание объекта `Thread` или `Runnable`, без вызова `start()`). -Стримы создаются на основе источников каких-либо, например классов из `java.util.Collection`. +Стримы создаются на основе каких-либо источников, например классов из `java.util.Collection`. Ассоциативные массивы (maps), например, `HashMap`, не поддерживаются. From 7a3b0225d7fc3d369dd7682e33add1a4639b5ebf Mon Sep 17 00:00:00 2001 From: ysemchuk Date: Mon, 31 May 2021 16:44:44 +0200 Subject: [PATCH 21/58] Update core.md --- core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.md b/core.md index d0c847e..9a94895 100644 --- a/core.md +++ b/core.md @@ -1247,7 +1247,7 @@ public native int hashCode(); Метод `hashCode()` необходим для вычисления хэш кода переданного в качестве входного параметра объекта. В Java это целое число, в более широком смысле - битовая строка фиксированной длины, полученная из массива произвольной длины. Этот метод реализован таким образом, что для одного и того же входного объекта, хэш код всегда будет одинаковым. Следует понимать, что в Java множество возможных хэш кодов ограничено типом `int`, а множество объектов ничем не ограничено. Из-за этого, вполне возможна ситуация, что хэш коды разных объектов могут совпасть: + если хэш коды разные, то и объекты гарантированно разные; -+ если хэш коды равны, то объекты могут не обязательно равны. ++ если хэш коды равны, то объекты не обязательно равны(могут быть разные). [к оглавлению](#java-core) From 36a4e9d06ab415794dba252b86aa82c371ef5f7c Mon Sep 17 00:00:00 2001 From: Oleg Poltoratskii <66324201+olegpoltora@users.noreply.github.com> Date: Tue, 29 Jun 2021 20:33:32 +0300 Subject: [PATCH 22/58] Update jcf.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сложность HashMap в случае плохой хэш-функции после Java 7 --- jcf.md | 1 + 1 file changed, 1 insertion(+) diff --git a/jcf.md b/jcf.md index 197074b..3b86aea 100644 --- a/jcf.md +++ b/jcf.md @@ -825,6 +825,7 @@ public class Q { ## Какое худшее время работы метода get(key) для ключа, которого нет в `HashMap`? ## Какое худшее время работы метода get(key) для ключа, который есть в `HashMap`? ___O(N)___. Худший случай - это поиск ключа в `HashMap`, вырожденного в список по причине совпадения ключей по `hashCode()` и для выяснения хранится ли элемент с определённым ключом может потребоваться перебор всего списка. +Но начиная с Java 7, после определенного числа элементов в списке, связный список преобразовывается в красно-черное дерево и сложность выборки, даже в случае плохой хеш-функции, не хуже _логарифмической_ _O(log(N))_ [к оглавлению](#java-collections-framework) From 7145db164fff7ac4147dfc5246bb010d26e41268 Mon Sep 17 00:00:00 2001 From: Oleg Poltoratskii <66324201+olegpoltora@users.noreply.github.com> Date: Tue, 29 Jun 2021 20:39:14 +0300 Subject: [PATCH 23/58] Update jcf.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Java 8, а не 7 --- jcf.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jcf.md b/jcf.md index 3b86aea..3b13d78 100644 --- a/jcf.md +++ b/jcf.md @@ -825,7 +825,8 @@ public class Q { ## Какое худшее время работы метода get(key) для ключа, которого нет в `HashMap`? ## Какое худшее время работы метода get(key) для ключа, который есть в `HashMap`? ___O(N)___. Худший случай - это поиск ключа в `HashMap`, вырожденного в список по причине совпадения ключей по `hashCode()` и для выяснения хранится ли элемент с определённым ключом может потребоваться перебор всего списка. -Но начиная с Java 7, после определенного числа элементов в списке, связный список преобразовывается в красно-черное дерево и сложность выборки, даже в случае плохой хеш-функции, не хуже _логарифмической_ _O(log(N))_ + +Но начиная с Java 8, после определенного числа элементов в списке, связный список преобразовывается в красно-черное дерево и сложность выборки, даже в случае плохой хеш-функции, не хуже _логарифмической_ _O(log(N))_ [к оглавлению](#java-collections-framework) From 39a7c96d3e953e0450dee2fc554ce535eb9005f0 Mon Sep 17 00:00:00 2001 From: Oleg Poltoratskii <66324201+olegpoltora@users.noreply.github.com> Date: Tue, 29 Jun 2021 19:18:23 +0300 Subject: [PATCH 24/58] Update jcf.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LinkedList - уточнение по сложности алгоритмов. --- jcf.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jcf.md b/jcf.md index 3b13d78..4424529 100644 --- a/jcf.md +++ b/jcf.md @@ -263,8 +263,10 @@ FILO, First-In-Last-Out («первым пришел, последним уше `LinkedList`: + на получение элемента по индексу или значению потребуется _линейное_ время _O(N)_; ++ но доступ к первому и последнему элементу списка всегда осуществляется за _константное_ время _O(1)_ — ссылки постоянно хранятся на первый и последний элемент; + на добавление и удаление в начало или конец списка потребуется _константное_ _O(1)_; + вставка или удаление в/из произвольного место _константное_ _O(1)_; ++ но поиск позиции вставки и удаления за _линейное_ время _O(N)_; + требует больше памяти для хранения такого же количества элементов, потому что кроме самого элемента хранятся еще указатели на следующий и предыдущий элементы списка. В целом, `LinkedList` в абсолютных величинах проигрывает `ArrayList` и по потребляемой памяти, и по скорости выполнения операций. `LinkedList` предпочтительно применять, когда нужны частые операции вставки/удаления или в случаях, когда необходимо гарантированное время добавления элемента в список. From d8613d6ca83e74043a38dc62bb2c3d3f6b9099b9 Mon Sep 17 00:00:00 2001 From: Andrey <49394356+KiselevichAndrey@users.noreply.github.com> Date: Mon, 9 Aug 2021 11:33:47 +0300 Subject: [PATCH 25/58] Update sql.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен более развернутый ответ на вопрос ## В чем различие между операторами `HAVING` и `WHERE`? --- sql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql.md b/sql.md index 6ec0ef8..a60b2dd 100644 --- a/sql.md +++ b/sql.md @@ -157,7 +157,7 @@ __CROSS JOIN (декартово произведение)__ [к оглавлению](#sql) ## В чем различие между операторами `HAVING` и `WHERE`? -`HAVING` используется как `WHERE`, но в другой части SQL-выражения и, соответственно, на другой стадии формирования ответа. +Основное отличие 'WHERE' от 'HAVING' заключается в том, что 'WHERE' сначала выбирает строки, а затем группирует их и вычисляет агрегатные функции (таким образом, она отбирает строки для вычисления агрегатов), тогда как 'HAVING' отбирает строки групп после группировки и вычисления агрегатных функций. Как следствие, предложение 'WHERE' не должно содержать агрегатных функций; не имеет смысла использовать агрегатные функции для определения строк для вычисления агрегатных функций. Предложение 'HAVING', напротив, всегда содержит агрегатные функции. (Строго говоря, вы можете написать предложение 'HAVING', не используя агрегаты, но это редко бывает полезно. То же самое условие может работать более эффективно на стадии 'WHERE'.) [к оглавлению](#sql) From edb18ddcde89bcd388d83b1c8bfe313fd982e644 Mon Sep 17 00:00:00 2001 From: Eugene Mamaev Date: Thu, 12 Aug 2021 10:24:13 +0300 Subject: [PATCH 26/58] =?UTF-8?q?=D0=A2=D0=B8=D0=BF=20=D1=83=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20push()=20=D0=B2=20=D0=BD=D0=B5?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BA=D0=B8=D1=80=D1=83=D1=8E=D1=89=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=BE=D1=87=D0=B5=D1=80=D0=B5=D0=B4=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/enhorse/java-interview/issues/86 Убрал ошибку компиляции с возвращаемым типом. --- concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concurrency.md b/concurrency.md index 0f4042f..f0cb7e8 100644 --- a/concurrency.md +++ b/concurrency.md @@ -812,7 +812,7 @@ __busy spin__ – это техника, которую программисты class NonBlockingStack { private final AtomicReference head = new AtomicReference<>(null); - Stack push(final T value) { + NonBlockingStack push(final T value) { final Element current = new Element(); current.value = value; Element recent; From a58bd3cddfd531388d6d9e844a475f18f15d89d1 Mon Sep 17 00:00:00 2001 From: Igor Tiulkanov <80449437+itiulkanov@users.noreply.github.com> Date: Fri, 17 Sep 2021 13:50:07 +0300 Subject: [PATCH 27/58] Update concurrency.md Fix the typo --- concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concurrency.md b/concurrency.md index f0cb7e8..a853abd 100644 --- a/concurrency.md +++ b/concurrency.md @@ -152,7 +152,7 @@ Java использует __вытесняющую многозадачност [к оглавлению](#Многопоточность) ## Что такое _ordering_, _as-if-serial semantics_, _sequential consistency_, _visibility_, _atomicity_, _happens-before_, _mutual exclusion_, _safe publication_? -__ordering__ механизм, который определяет, когда один поток может увидеть _out-of-order_ (неверный) порядок исполнения инструкций другого потока. CPU для для повышения производительности может переупорядочивать процессорные инструкции и выполнять их в произвольном порядке до тех пор пока для потока внутри не будет видно никаких отличий. Гарантия, предоставляемая этим механизмом, называется __as-if-serial semantics__. +__ordering__ механизм, который определяет, когда один поток может увидеть _out-of-order_ (неверный) порядок исполнения инструкций другого потока. CPU для повышения производительности может переупорядочивать процессорные инструкции и выполнять их в произвольном порядке до тех пор пока для потока внутри не будет видно никаких отличий. Гарантия, предоставляемая этим механизмом, называется __as-if-serial semantics__. __sequential consistency__ - то же что и _as-if-serial semantics_, гарантия того, что в рамках одного потока побочные эффекты от всех операций будут такие, как будто все операции выполняются последовательно. From 77061c8ec49bfc79e59f8a0849f003be788ceb95 Mon Sep 17 00:00:00 2001 From: Mike Scherbakov <62207753+ScherbakovMike@users.noreply.github.com> Date: Tue, 25 Jan 2022 07:22:43 +0300 Subject: [PATCH 28/58] Update java8.md some small mistake --- java8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java8.md b/java8.md index ac2ea4e..fe86d1a 100644 --- a/java8.md +++ b/java8.md @@ -440,7 +440,7 @@ class Licence implements Paper { ## Что такое `static` метод интерфейса? Статические методы интерфейса похожи на методы по умолчанию, за исключением того, что для них отсутствует возможность переопределения в классах, реализующих интерфейс. -+ Статические методы в интерфейсе являются частью интерфейса без возможности использовать их для объектов класса реализации; ++ Статические методы в интерфейсе являются частью интерфейса без возможности переопределить их для объектов класса реализации; + Методы класса `java.lang.Object` нельзя переопределить как статические; + Статические методы в интерфейсе используются для обеспечения вспомогательных методов, например, проверки на null, сортировки коллекций и т.д. From 166fa2bbf0e593e4ad772498de2b0c7ff1859684 Mon Sep 17 00:00:00 2001 From: Yaroslav Kivaev Date: Sun, 13 Mar 2022 08:26:54 +0300 Subject: [PATCH 29/58] Fix grammar mistake --- web.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web.md b/web.md index d7769c8..8e5daad 100644 --- a/web.md +++ b/web.md @@ -173,7 +173,7 @@ __FTP, File Transfer Protocol (Протокол передачи файлов)__ [к оглавлению](#Основы-web) ## Чем отличаются методы _GET_ и _POST_? -__GET__ передает данные серверу используя URL, тогда как __POST__ передает данные, используя тело HTTP запроса. Длина URL ограничена 1024 символами, это и будет верхним ограничением для данных, которые можно отослать через GET. POST может отправлять гораздо большие объемы данных. Лимит устанавливается web-server и составляет обычно около 2 Mb. +__GET__ передает данные серверу, используя URL, тогда как __POST__ передает данные, используя тело HTTP запроса. Длина URL ограничена 1024 символами, это и будет верхним ограничением для данных, которые можно отослать через GET. POST может отправлять гораздо большие объемы данных. Лимит устанавливается web-server и составляет обычно около 2 Mb. Передача данных методом POST более безопасна, чем методом GET, так как секретные данные (например пароль) не отображаются напрямую в web-клиенте пользователя, в отличии от URL, который виден почти всегда. Иногда это преимущество превращается в недостаток - вы не сможете послать данные за кого-то другого. From e6583ab0382d4ad7a6a26e44ff6315c6fb2b0e5e Mon Sep 17 00:00:00 2001 From: Enchased Horse Date: Sat, 28 May 2022 12:41:12 +0300 Subject: [PATCH 30/58] Close #104 --- core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.md b/core.md index 9a94895..11ac5ce 100644 --- a/core.md +++ b/core.md @@ -1207,7 +1207,7 @@ __Рефлексия (Reflection)__ - это механизм получения ## Правила переопределения метода `Object.equals()`. 1. Использование оператора `==` для проверки, является ли аргумент ссылкой на указанный объект. Если является, возвращается `true`. Если сравниваемый объект `== null`, должно вернуться `false`. -2. Использование оператор `instanceof` и вызова метода `getClass()` для проверки, имеет ли аргумент правильный тип. Если не имеет, возвращается `false`. +2. Использование вызова метода `getClass()` для проверки, имеет ли аргумент правильный тип. Если не имеет, возвращается `false`. 3. Приведение аргумента к правильному типу. Поскольку эта операция следует за проверкой `instanceof` она гарантированно будет выполнена. 4. Обход всех значимых полей класса и проверка того, что значение поля в текущем объекте и значение того же поля в проверяемом на эквивалентность аргументе соответствуют друг другу. Если проверки для всех полей прошли успешно, возвращается результат `true`, в противном случае - `false`. From 1987fcad3b20baba25968a78dc0efc42facb97d8 Mon Sep 17 00:00:00 2001 From: Ivan B Date: Tue, 31 May 2022 19:22:32 +0400 Subject: [PATCH 31/58] Fix answer about static modifier --- core.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core.md b/core.md index 11ac5ce..0b14f05 100644 --- a/core.md +++ b/core.md @@ -385,6 +385,7 @@ public class TestClass { + полям; + методам; + вложенным классам; ++ блокам инициализации; + членам секции `import`. [к оглавлению](#java-core) From 8bc421e0605c4fb57864afe23eb3cf6b1fc693a9 Mon Sep 17 00:00:00 2001 From: Ivan B Date: Fri, 24 Jun 2022 05:39:33 +0400 Subject: [PATCH 32/58] Fix a spelling mistake --- jcf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jcf.md b/jcf.md index 4424529..d024e8a 100644 --- a/jcf.md +++ b/jcf.md @@ -892,7 +892,7 @@ __Один__ новый объект статического вложенног ## Для `Enum` есть специальный класс `java.util.EnumSet`. Зачем? Чем авторов не устраивал `HashSet` или `TreeSet`? `EnumSet` - это реализация интерфейса `Set` для использования с перечислениями (`Enum`). В структуре данных хранятся объекты только одного типа `Enum`, указываемого при создании. Для хранения значений `EnumSet` использует массив битов (_bit vector_), - это позволяет получить высокую компактность и эффективность. Проход по `EnumSet` осуществляется согласно порядку объявления элементов перечисления. -Все основные операции выполняются за _O(1)_ и обычно (но негарантированно) быстрей аналогов из `HashSet`, а пакетные операции (_bulk operations_), такие как `containsAll()` и `retainAll()` выполняются даже горазда быстрей. +Все основные операции выполняются за _O(1)_ и обычно (но негарантированно) быстрей аналогов из `HashSet`, а пакетные операции (_bulk operations_), такие как `containsAll()` и `retainAll()` выполняются даже гораздо быстрей. Помимо всего `EnumSet` предоставляет множество статических методов инициализации для упрощенного и удобного создания экземпляров. From ad1c2cae14518f0d439136795b48bc4bf31f6831 Mon Sep 17 00:00:00 2001 From: Daniil Gavshin <48032646+dgavshin@users.noreply.github.com> Date: Tue, 18 Oct 2022 22:50:30 +0300 Subject: [PATCH 33/58] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=20=D1=81=D0=BB=D0=BE=D0=B2=D0=BE=20?= =?UTF-8?q?=D0=B2=20=D0=BF=D1=80=D0=B5=D0=B4=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jvm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jvm.md b/jvm.md index 27d0db1..3b094ba 100644 --- a/jvm.md +++ b/jvm.md @@ -77,7 +77,7 @@ JVM работает с примитивными значениями (целы Это важная особенность для: - реализация скриптовых языков; - использование bean builders; - - добавить пользовательскую расширение; + - добавить пользовательское расширение; - позволяя нескольким пространствам имен общаться. Например, это одна из основ протоколов CORBA / RMI; * изменить способ загрузки байт-кода (например, можно использовать зашифрованный байт-код класса Java); * модифицировать загруженный байт-код (например, для переплетения аспектов во время загрузки при использовании аспектно-ориентированного программирования); From 6baa90d0445166ac87645c5947ae2b56e85eae25 Mon Sep 17 00:00:00 2001 From: SooRya2 <89139760+SooRya2@users.noreply.github.com> Date: Thu, 12 Jan 2023 12:41:47 +0530 Subject: [PATCH 34/58] Adding a new link for additional materials New Interview questions link for Hibernate under Additional materials. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7065c6c..19b287f 100644 --- a/README.md +++ b/README.md @@ -753,6 +753,7 @@ + [Spring Boot Interview Questions](https://www.baeldung.com/spring-boot-interview-questions) + [Top Spring Framework Interview Questions](https://www.baeldung.com/spring-interview-questions) + [Spring Interview Questions](https://www.interviewbit.com/spring-interview-questions/) ++ [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) [к оглавлению](#Вопросы-для-собеседования-на-java-developer) From 6577c6ae7efe8a6441a193173466551b3329406b Mon Sep 17 00:00:00 2001 From: Olga Larina Date: Thu, 16 Mar 2023 15:06:31 +0300 Subject: [PATCH 35/58] fix HashSet in jcf --- jcf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jcf.md b/jcf.md index d024e8a..302b137 100644 --- a/jcf.md +++ b/jcf.md @@ -105,7 +105,7 @@ _«Коллекция»_ - это структура данных, набор к + `Vector` — реализация динамического массива объектов, методы которой синхронизированы. + `Stack` — реализация стека LIFO (last-in-first-out). + `Set` (сет) описывает неупорядоченную коллекцию, не содержащую повторяющихся элементов. Реализации: - + `HashSet` - использует HashMap для хранения данных. В качестве ключа и значения используется добавляемый элемент. Из-за особенностей реализации порядок элементов не гарантируется при добавлении. + + `HashSet` - использует HashMap для хранения данных. В качестве ключа используется добавляемый элемент, в качестве значения - заглушка Object. Из-за особенностей реализации порядок элементов не гарантируется при добавлении. + `LinkedHashSet` — гарантирует, что порядок элементов при обходе коллекции будет идентичен порядку добавления элементов. + `TreeSet` — предоставляет возможность управлять порядком элементов в коллекции при помощи объекта `Comparator`, либо сохраняет элементы с использованием «natural ordering». + `Queue` (очередь) предназначена для хранения элементов с предопределённым способом вставки и извлечения FIFO (first-in-first-out): From 741ccdee18cc50ad45d5d84a50d842808e39a00a Mon Sep 17 00:00:00 2001 From: CoffeeAfterWakingUp <76391010+CoffeeAfterWakingUp@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:25:57 +0600 Subject: [PATCH 36/58] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D0=B8=D0=BD=D1=82=D0=B0=D0=BA=D1=81=D0=B8=D1=81?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80?= =?UTF-8?q?=D1=83=D0=BA=D1=82=D0=BE=D1=80=D0=B0=20=D0=BF=D0=BE=20=D1=83?= =?UTF-8?q?=D0=BC=D0=BE=D0=BB=D1=87=D0=B0=D0=BD=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Неправильный синтаксис для конструктора по умолчанию --- core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.md b/core.md index 0b14f05..e17a9ae 100644 --- a/core.md +++ b/core.md @@ -1121,7 +1121,7 @@ __Конструктор__ — это специальный метод, у ко Если у какого-либо класса не определить конструктор, то компилятор сгенерирует конструктор без аргументов - так называемый __«конструктор по умолчанию»__. ```java -public class ClassName() {} +public ClassName() {} ``` Если у класса уже определен какой-либо конструктор, то конструктор по умолчанию создан не будет и, если он необходим, его нужно описывать явно. From 2a49782f208b330b4d794675e50c438a73e935b3 Mon Sep 17 00:00:00 2001 From: liaombro <85120539+liaombro@users.noreply.github.com> Date: Fri, 24 Mar 2023 14:55:44 +0300 Subject: [PATCH 37/58] Update java8.md fix typo --- java8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java8.md b/java8.md index fe86d1a..904d885 100644 --- a/java8.md +++ b/java8.md @@ -547,7 +547,7 @@ Stream fromGenerate = Stream.generate(() -> "0"); [к оглавлению](#java-8) ## Для чего нужен метод `collect()` в стримах? -Метод `collect()` является конечной операцией, которая используется для представление результата в виде коллекции или какой-либо другой структуры данных. +Метод `collect()` является конечной операцией, которая используется для представления результата в виде коллекции или какой-либо другой структуры данных. `collect()` принимает на вход `Collector<Тип_источника, Тип_аккумулятора, Тип_результата>`, который содержит четыре этапа: _supplier_ - инициализация аккумулятора, _accumulator_ - обработка каждого элемента, _combiner_ - соединение двух аккумуляторов при параллельном выполнении, _[finisher]_ - необязательный метод последней обработки аккумулятора. В Java 8 в классе `Collectors` реализовано несколько распространённых коллекторов: From a303da3a7090479a1046f1f2f768ef2d75481ffe Mon Sep 17 00:00:00 2001 From: Yuriy Kiselev Date: Tue, 11 Apr 2023 23:50:03 +0300 Subject: [PATCH 38/58] non-blocking ArrayList fix --- concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concurrency.md b/concurrency.md index a853abd..78d3db7 100644 --- a/concurrency.md +++ b/concurrency.md @@ -908,7 +908,7 @@ class NonBlockingArrayList { if (item == null) { needsModification = content[index] != null; } else { - needsModification = item.equals(content[index]); + needsModification = !item.equals(content[index]); } } if (needsModification) { From d4c6d9de1f36b0fa4b31700b1935bf11355ebb7d Mon Sep 17 00:00:00 2001 From: KhokhlovTimur <90100391+KhokhlovTimur@users.noreply.github.com> Date: Fri, 9 Jun 2023 15:10:52 +0300 Subject: [PATCH 39/58] Update servlets.md --- servlets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servlets.md b/servlets.md index 0f90fb3..d34d240 100644 --- a/servlets.md +++ b/servlets.md @@ -822,7 +822,7 @@ JSP расширяет технологию сервлетов обеспечи [к оглавлению](#servlets-jsp-jstl) ## Расскажите об этапах (фазах) жизненного цикла JSP. -Если посмотреть код внутри созданной JSP страницы, то он будет выглядеть как HTML и не будет похож на java класс. Конвертацией JSP страниц в HTML код занимается контейнер, который так же создает и сервлет для использования в веб приложении. +Если посмотреть код внутри созданной JSP страницы, то он будет выглядеть как HTML и не будет похож на java класс. Конвертацией JSP страниц в HTML код занимается контейнер, который также создает и сервлет для использования в веб приложении. Жизненный цикл JSP состоит из нескольких фаз, которыми руководит JSP контейнер: From 8663c985a3b3698ea67ae88f8ce5685bd5405aa7 Mon Sep 17 00:00:00 2001 From: Rompet Date: Sat, 10 Jun 2023 05:20:03 +0800 Subject: [PATCH 40/58] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B5=20=D1=81?= =?UTF-8?q?=D0=B2=D1=8F=D0=B7=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oop.md b/oop.md index cd803c1..baa3e7b 100644 --- a/oop.md +++ b/oop.md @@ -375,7 +375,7 @@ __«имеет»__ подразумевает ассоциацию (агрега В свою очередь, _позднее связывание (late binding)_ это связывание, проводимое непосредственно во время выполнения программы, в зависимости от типа объекта. Позднее связывание также называют _динамическим (dynamic)_ или _связыванием на стадии выполнения (runtime binding)_. В языках, реализующих позднее связывание, должен существовать механизм определения фактического типа объекта во время работы программы, для вызова подходящего метода. Иначе говоря, компилятор не знает тип объекта, но механизм вызова методов определяет его и вызывает соответствующее тело метода. Механизм позднего связывания зависит от конкретного языка, но нетрудно предположить, что для его реализации в объекты должна включаться какая-то дополнительная информация. -Для всех методов Java используется механизм позднего (динамического) связывания, если только метод не был объявлен как `final` (приватные методы являются `final` по умолчанию). +Для всех методов Java используется механизм позднего (динамического) связывания, если только метод не был объявлен как `final`, `static` или `private` (приватные методы являются `final` по умолчанию). [к оглавлению](#ООП) From 53ebad83f689f41c934cc8f1ca49ed5323e3304e Mon Sep 17 00:00:00 2001 From: Nikita Bulgakov <110889453+sepxxx@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:13:33 +0300 Subject: [PATCH 41/58] Update core.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ошибка в вопросе про String. Не все объекты типа String хранятся в string pool. --- core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.md b/core.md index e17a9ae..b649122 100644 --- a/core.md +++ b/core.md @@ -1032,7 +1032,7 @@ __Автоупаковка__ - это механизм неявной иници ## Какие есть особенности класса `String`? + Это неизменяемый (immutable) и финализированный тип данных; -+ Все объекты класса `String` JVM хранит в пуле строк; ++ Строки-литералы, интернированные объекты класса `String` JVM хранит в пуле строк; + Объект класса `String` можно получить, используя двойные кавычки; + Можно использовать оператор `+` для конкатенации строк; + Начиная с Java 7 строки можно использовать в конструкции `switch`. From a94635cdf23236f103029f722faf33d9fa2c8d25 Mon Sep 17 00:00:00 2001 From: Egor Baranov <49813134+egor-baranov@users.noreply.github.com> Date: Fri, 10 Feb 2023 01:25:27 +0300 Subject: [PATCH 42/58] Update concurrency.md --- concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/concurrency.md b/concurrency.md index 78d3db7..f4a1d20 100644 --- a/concurrency.md +++ b/concurrency.md @@ -784,7 +784,7 @@ __busy spin__ – это техника, которую программисты + Всегда давайте значимые имена своим потокам. Процесс отладки, нахождения ошибок или отслеживание исключения в многопоточном коде – довольно сложная задача. `OrderProcessor`, `QuoteProcessor` или `TradeProcessor` намного информативнее, чем `Thread1`, `Thread2` и `Thread3`. Имя должно отражать задачу, выполняемую данным потоком. + Избегайте блокировок или старайтесь уменьшить масштабы синхронизации. Блокировка затратна, а переключение контекста ещё более ресурсоёмко. Пытайтесь избегать синхронизации и блокировки насколько это возможно, и организуйте критическую секцию в минимально необходимом объёме. Поэтому синхронизированный блок всегда предпочительней синхронизированного метода, дополнительно наделяя возможностью абсолютного контроля над масштабом блокировки. + Обрабатывайте прерывание потока с особой тщательностью. Нет ничего хуже оставшегося заблокированным ресурса или системы в неконстистентном, по причине неподтверждённой транзакции, состоянии. -+ Помните об обработке исключений. Выброшенные `InterruptedException` должны быть адекватно обработаны, а не просто подавлены. Так же не стоит пренебрегать `Thread.UncaughtExceptionHandler`. При использовании пула потоков необходимо помнить, что он зачастую просто «проглатывает» исключения. Так, если вы отправили на выполнение `Runnable` нужно обязательно поместить код выполнения задачи внутрь блока `try-catch`. Если в очередь пула помещается `Callable`, необходимо удостоверится, что результат выполнения всегда изымается помощью блокирующего `get()`, чтобы в случае возникновения существовала возможнотсь заново выбросить произошедшее исключение. ++ Помните об обработке исключений. Выброшенные `InterruptedException` должны быть адекватно обработаны, а не просто подавлены. Так же не стоит пренебрегать `Thread.UncaughtExceptionHandler`. При использовании пула потоков необходимо помнить, что он зачастую просто «проглатывает» исключения. Так, если вы отправили на выполнение `Runnable` нужно обязательно поместить код выполнения задачи внутрь блока `try-catch`. Если в очередь пула помещается `Callable`, необходимо удостоверится, что результат выполнения всегда изымается помощью блокирующего `get()`, чтобы в случае возникновения существовала возможность заново выбросить произошедшее исключение. + Между синхронизаторами и `wait()` и `notify()` следует выбирать синхронизаторы. Во-первых, синхронизаторы, типа `CountDownLatch`, `Semaphore`, `CyclicBarrier` или `Exchanger` упрощают написание кода. Очень сложно реализовывать комплексный управляющий поток, используя `wait()` и `notify()`. Во-вторых, эти классы написаны и поддерживаются настоящими мастерами своего дела и есть шанс, что в последующих версиях JDK они будут оптимизированы изнутри или заменены более производительной внешней реализацией. + Почти всегда использование Concurrent сollection выгоднее использования Synchronized сollection, т.к. первые более современны (используют все доступные на момент их написания новшества языка) и масштабируемы, чем их синхронизированые аналоги. From 634ee86f09aa93b255f48a01551876eadce8450c Mon Sep 17 00:00:00 2001 From: Mike <68198830+mikhail43435@users.noreply.github.com> Date: Fri, 9 Dec 2022 18:27:05 +0300 Subject: [PATCH 43/58] =?UTF-8?q?Update=20core.md=20-=20=D1=83=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=84=D0=BE=D0=BB=D1=82=D0=BD=D1=8B=D0=BC=20=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit источник https://docs.oracle.com/javase/specs/jls/se14/html/jls-4.html#jls-4.12.4 --- core.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core.md b/core.md index b649122..6221dfc 100644 --- a/core.md +++ b/core.md @@ -149,7 +149,12 @@ __public__ (публичный): класс/члены класса доступ [к оглавлению](#java-core) ## Какими значениями инициализируются переменные по умолчанию? -+ Числа инициализируются `0` или `0.0`; ++ `byte` — `(byte)0`; ++ `short` — `(short)0`; ++ `int` — `0`; ++ `long` — `0L`; ++ `floatg` — `0f`; ++ `double` — `0d`; + `char` — `\u0000`; + `boolean` — `false`; + Объекты (в том числе `String`) — `null`. From 26cec8885864f17e6b7d4e519c2a484960943b4a Mon Sep 17 00:00:00 2001 From: esylva <82966354+esylva@users.noreply.github.com> Date: Thu, 13 Oct 2022 18:37:43 +0300 Subject: [PATCH 44/58] Update test.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Исправлены опечатки --- test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.md b/test.md index a89dc88..f1f2b21 100644 --- a/test.md +++ b/test.md @@ -76,7 +76,7 @@ __Фикстуры (fixtures)__ - состояние среды тестиров + `@BeforeClass` - определяет код, который должен единожды выполниться перед запуском набора тестовых методов. + `@AfterClass` - код, выполняемый один раз после исполнения набора тестовых методов. -+ `@Before` - определяет код, который должен выполняться каждый раз перд запуском любого тестовым методом. ++ `@Before` - определяет код, который должен выполняться каждый раз перед запуском любого тестового метода. + `@After` - код, выполняемый каждый раз после исполнения любого тестового метода. [к оглавлению](#Тестирование) From b640360737b7fe0602c95232de855d924b852512 Mon Sep 17 00:00:00 2001 From: comavp Date: Mon, 19 Feb 2024 22:40:48 +0400 Subject: [PATCH 45/58] Fix inappropriate word in jcd.md --- jcf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jcf.md b/jcf.md index 302b137..613b042 100644 --- a/jcf.md +++ b/jcf.md @@ -722,7 +722,7 @@ PhantomReference при вызове метода `get()` возвращает Для метода цепочек коэффициент заполнения может быть больше 1 и с увеличением числа элементов производительность убывает линейно. Такие таблицы удобно использовать, если заранее неизвестно количество хранимых элементов, либо их может быть достаточно много, что приводит к большим значениям коэффициента заполнения. -Среди методов открытой реализации различают: +Среди методов открытой адресации различают: + линейное пробирование; + квадратичное пробирование; From 669451fd221d8584b7e72fbdd381b0a6aaf3a216 Mon Sep 17 00:00:00 2001 From: comavp Date: Tue, 20 Feb 2024 22:39:21 +0400 Subject: [PATCH 46/58] Add correct description of default Object#hashCode() method Closes #118 --- core.md | 6 ++++-- jcf.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core.md b/core.md index 6221dfc..f20e28b 100644 --- a/core.md +++ b/core.md @@ -1241,12 +1241,14 @@ public boolean equals(Object obj) { } ``` -Реализация метода `Object.hashCode()` описана как `native`, т.е. определенной не с помощью Java кода и обычно возвращает адрес объекта в памяти: +Реализация метода `Object.hashCode()` описана как `native`, т.е. определенной не с помощью Java кода и в общем случае зависит от реализации JVM: ```java public native int hashCode(); ``` +В HotSpot JVM хэш код по умолчанию вычисляется с помощью алгоритма генерации простых чисел - Xorshift. + [к оглавлению](#java-core) ## Для чего нужен метод `hashCode()`? @@ -1288,7 +1290,7 @@ public native int hashCode(); [к оглавлению](#java-core) ## Можно ли так реализовать метод `equals(Object that) {return this.hashCode() == that.hashCode()}`? -Строго говоря нельзя, поскольку метод `hashCode()` не гарантирует уникальность значения для каждого объекта. Однако для сравнения экземпляров класса `Object` такой код допустим, т.к. метод `hashCode()` в классе `Object` возвращает уникальные значения для разных объектов (его вычисление основано на использовании адреса объекта в памяти). +Строго говоря нельзя, поскольку метод `hashCode()` не гарантирует уникальность значения для каждого объекта. Однако для сравнения экземпляров класса `Object` такой код допустим, т.к. метод `hashCode()` в классе `Object` возвращает уникальные значения для разных объектов (его вычисление основано на использовании алгоритма генерации случайных чисел). [к оглавлению](#java-core) diff --git a/jcf.md b/jcf.md index 613b042..0450398 100644 --- a/jcf.md +++ b/jcf.md @@ -810,7 +810,7 @@ public class Q { [к оглавлению](#java-collections-framework) ## Почему нельзя использовать `byte[]` в качестве ключа в `HashMap`? -Хэш-код массива не зависит от хранимых в нем элементов, а присваивается при создании массива (метод вычисления хэш-кода массива не переопределен и вычисляется по стандартному `Object.hashCode()` на основании адреса массива). Так же у массивов не переопределен `equals` и выполняется сравнение указателей. Это приводит к тому, что обратиться к сохраненному с ключом-массивом элементу не получится при использовании другого массива такого же размера и с такими же элементами, доступ можно осуществить лишь в одном случае — при использовании той же самой ссылки на массив, что использовалась для сохранения элемента. +Хэш-код массива не зависит от хранимых в нем элементов, а присваивается при создании массива (метод вычисления хэш-кода массива не переопределен и вычисляется по стандартному `Object.hashCode()` на основе алгоритма генерации простых чисел). Так же у массивов не переопределен `equals` и выполняется сравнение указателей. Это приводит к тому, что обратиться к сохраненному с ключом-массивом элементу не получится при использовании другого массива такого же размера и с такими же элементами, доступ можно осуществить лишь в одном случае — при использовании той же самой ссылки на массив, что использовалась для сохранения элемента. [к оглавлению](#java-collections-framework) From d4e407b0b35dabcdb1a8c2d476c81519d87c27ed Mon Sep 17 00:00:00 2001 From: Anton Plankin <45337874+comavp@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:28:22 +0400 Subject: [PATCH 47/58] Add answer to the question about role of Comparable in HashMap (#156) * Add answer to the question about role of Comparable in HashMap after Java 8 --- README.md | 1 + jcf.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 19b287f..13dca74 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ + [Каково максимальное число значений `hashCode()`?](jcf.md#Каково-максимальное-число-значений-hashcode) + [Какое худшее время работы метода get(key) для ключа, которого нет в `HashMap`?](jcf.md#Какое-худшее-время-работы-метода-getkey-для-ключа-которого-нет-в-hashmap) + [Какое худшее время работы метода get(key) для ключа, который есть в `HashMap`?](jcf.md#Какое-худшее-время-работы-метода-getkey-для-ключа-который-есть-в-hashmap) ++ [Почему несмотря на то, что ключ в `HashMap` не обязан реализовывать интерфейс `Comparable`, двусвязный список всегда удается преобразовать в красно-черное-дерево?](jcf.md#Почему-несмотря-на-то-что-ключ-в-HashMap-не-обязан-реализовывать-интерфейс-Comparable-двусвязный-список-всегда-удается-преобразовать-в-красно-черное-дерево) + [Сколько переходов происходит в момент вызова `HashMap.get(key)` по ключу, который есть в таблице?](jcf.md#Сколько-переходов-происходит-в-момент-вызова-hashmapgetkey-по-ключу-который-есть-в-таблице) + [Сколько создается новых объектов, когда вы добавляете новый элемент в `HashMap`?](jcf.md#Сколько-создается-новых-объектов-когда-вы-добавляете-новый-элемент-в-hashmap) + [Как и когда происходит увеличение количества корзин в `HashMap`?](jcf.md#Как-и-когда-происходит-увеличение-количества-корзин-в-hashmap) diff --git a/jcf.md b/jcf.md index 0450398..d856cd9 100644 --- a/jcf.md +++ b/jcf.md @@ -63,6 +63,7 @@ + [Каково максимальное число значений `hashCode()`?](#Каково-максимальное-число-значений-hashcode) + [Какое худшее время работы метода get(key) для ключа, которого нет в `HashMap`?](#Какое-худшее-время-работы-метода-getkey-для-ключа-которого-нет-в-hashmap) + [Какое худшее время работы метода get(key) для ключа, который есть в `HashMap`?](#Какое-худшее-время-работы-метода-getkey-для-ключа-который-есть-в-hashmap) ++ [Почему несмотря на то, что ключ в `HashMap` не обязан реализовывать интерфейс `Comparable`, двусвязный список всегда удается преобразовать в красно-черное-дерево?](#Почему-несмотря-на-то-что-ключ-в-HashMap-не-обязан-реализовывать-интерфейс-Comparable-двусвязный-список-всегда-удается-преобразовать-в-красно-черное-дерево) + [Сколько переходов происходит в момент вызова `HashMap.get(key)` по ключу, который есть в таблице?](#Сколько-переходов-происходит-в-момент-вызова-hashmapgetkey-по-ключу-который-есть-в-таблице) + [Сколько создается новых объектов, когда вы добавляете новый элемент в `HashMap`?](#Сколько-создается-новых-объектов-когда-вы-добавляете-новый-элемент-в-hashmap) + [Как и когда происходит увеличение количества корзин в `HashMap`?](#Как-и-когда-происходит-увеличение-количества-корзин-в-hashmap) @@ -832,6 +833,20 @@ ___O(N)___. Худший случай - это поиск ключа в `HashMap [к оглавлению](#java-collections-framework) +## Почему несмотря на то, что ключ в `HashMap` не обязан реализовывать интерфейс `Comparable`, двусвязный список всегда удается преобразовать в красно-черное дерево? +Красно-черное дерево - это самобалансирующееся бинарное дерево поиска. Это означает, что для его построения нужно уметь сравнивать элементы между собой. + +В Java обычно сравнение объектов происходит с помощью метода `compareTo()`, который определен в интерфейсе `Comparable`. На первый взгляд кажется логичным, если бы после Java 8 у ключа в `HashMap` появилось дополнительное требование - реализовывать `Comparable`. + +Чтобы избежать этого, используется следующий алгоритм при сравнении ключей: +1. Сначала делается попытка сравнить хэши ключей +2. Если хэши равны и оба ключа реализуют `Comparable`, то для сравнения вызывается метод `compareTo()` +3. Если ключи не реализуют `Comparable`, то сравнение происходит с помощью метода `tieBreakOrder()`, в котором + + сначала будет совершена попытка сравнить ключи через названия их классов (`getClass().getName()`) + + если ключи являются экземплярами одного класса, то сравниваться будут результаты метода `System.identityHashCode()` + +[к оглавлению](#java-collections-framework) + ## Сколько переходов происходит в момент вызова `HashMap.get(key)` по ключу, который есть в таблице? + ключ равен `null`: __1__ - выполняется единственный метод `getForNullKey()`. + любой ключ отличный от `null`: __4__ - вычисление хэш-кода ключа; определение номера корзины; поиск значения; возврат значения. From d73ae9ea19a0f28ce7f5eb80955abd76409abec4 Mon Sep 17 00:00:00 2001 From: eliseevdry <47399611+eliseevdry@users.noreply.github.com> Date: Wed, 24 Apr 2024 08:43:26 +0300 Subject: [PATCH 48/58] Add info to synchronize answers (#160) --- concurrency.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/concurrency.md b/concurrency.md index f4a1d20..89b0ed6 100644 --- a/concurrency.md +++ b/concurrency.md @@ -558,6 +558,8 @@ __Куча__ – общий участок памяти, который дели ## Как поделиться данными между двумя потоками? Данными между потоками возможно делиться, используя общий объект или параллельные структуры данных, например `BlockingQueue`. +Класс синхронизатор `Exchanger` предназначен для обмена данными между потоками. Он параметризуется типом данных, которыми потоки должны обмениваться. +Обмен данными производится с помощью единственного метода этого класса exchange(). Для работы нужно передать в конструкторы thread-ов экземпляр класса Exchanger и обращаться к нему в методе run(). Этот метод блокирует поток до того момента, пока другой поток не передаст в Exchanger свои данные. [к оглавлению](#Многопоточность) @@ -621,7 +623,7 @@ finally { [к оглавлению](#Многопоточность) ## Что такое `ReadWriteLock`? -`ReadWriteLock` – это интерфейс расширяющий базовый интерфейс `Lock`. Используется для улучшения производительности в многопоточном процессе и оперирует парой связанных блокировок (одна - для операций чтения, другая - для записи). Блокировка чтения может удерживаться одновременно несколькими читающими потоками, до тех пор, пока не появится записывающий. Блокировка записи является эксклюзивеной. +`ReadWriteLock` – это интерфейс расширяющий базовый интерфейс `Lock`. Используется для улучшения производительности в многопоточном процессе и оперирует парой связанных блокировок (одна - для операций чтения, другая - для записи). Блокировка чтения может удерживаться одновременно несколькими читающими потоками, до тех пор, пока не появится записывающий. Блокировка записи является эксклюзивной. Существует реализующий интерфейс `ReadWriteLock` класс `ReentrantReadWriteLock`, который поддерживает до 65535 блокировок записи и до стольки же блокировок чтения. From 9a0df73a9bdab1fbe2a6785b0d2f1dae0a6bfa8d Mon Sep 17 00:00:00 2001 From: Danil Pudovkin <99204984+dapudovkin@users.noreply.github.com> Date: Wed, 20 Nov 2024 10:04:28 +0500 Subject: [PATCH 49/58] =?UTF-8?q?=D0=92=D0=BE=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D1=8B=20=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=D0=BC=D1=83=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=BC=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8E=20(#162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * reactive programming & reactive streams concept * backpressure, observables, subscription, operators * fix style * update README.md * Add kafka questions * Add kafka broker, producer architecture + add topic settings * Add kafka producer example config * Add kafka consumer * Update table of contents * fix style * Add kafka interview questions * Update README.md * Update Kafka questions style * Update Kafka --------- Co-authored-by: Danil Pudovkin --- README.md | 79 +++ kafka.md | 1420 +++++++++++++++++++++++++++++++++++++++++++++++++++ reactive.md | 584 +++++++++++++++++++++ 3 files changed, 2083 insertions(+) create mode 100644 kafka.md create mode 100644 reactive.md diff --git a/README.md b/README.md index 13dca74..dc9ccc8 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ + [Потоки ввода-вывода в Java](#Потоки-вводавывода-в-java) ![icon][done] + [Сериализация](#Сериализация) ![icon][done] + [Многопоточность](#Многопоточность) ![icon][done] ++ [Реактивное программирование](#реактивное-программирование) ![icon][done] + [Servlets, JSP, JSTL](#servlets-jsp-jstl) ![icon][done] + [Базы данных](#Базы-данных) ![icon][done] + [SQL](#sql) ![icon][done] @@ -24,6 +25,7 @@ + [Основы CSS](#Основы-css) ![icon][done] + [Основы Web](#Основы-web) ![icon][done] + [Дополнительные материалы](#Дополнительные-материалы) ![icon][done] ++ [Apache Kafka](#apache-kafka) ![icon][done] [done]:done.png @@ -445,6 +447,20 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) +## Реактивное программирование + +* [Что такое реактивное программирование и чем оно отличается от процедурного программирования?](reactive.md#что-такое-реактивное-программирование-и-чем-оно-отличается-от-процедурного-программирования) +* [Объясните концепцию потоков данных в реактивном программировании](reactive.md#объясните-концепцию-потоков-данных-в-реактивном-программировании) +* [Что такое паттерн Observer и как он лежит в основе реактивного программирования?](reactive.md#что-такое-паттерн-observer-и-как-он-лежит-в-основе-реактивного-программирования) +* [Опишите роль Observable и Observer в реактивном программировании](reactive.md#опишите-роль-observable-и-observer-в-реактивном-программировании) +* [Что такое backpressure в контексте реактивного программирования?](reactive.md#что-такое-backpressure-в-контексте-реактивного-программирования) +* [Объясните разницу между Hot и Cold Observable](reactive.md#объясните-разницу-между-hot-и-cold-observable) +* [Какова роль Подписки в реактивном программировании?](reactive.md#какова-роль-подписки-в-реактивном-программировании) +* [Как отписаться от потока для предотвращения утечки памяти?](reactive.md#как-отписаться-от-потока-для-предотвращения-утечки-памяти) +* [Какие есть операторы в Project Reactor и для чего они используются?](reactive.md#какие-есть-операторы-в-project-reactor-и-для-чего-они-используются) + +[к оглавлению](#Вопросы-для-собеседования-на-java-developer) + ## Servlets, JSP, JSTL + [Что такое _«сервлет»_?](servlets.md#Что-такое-сервлет) + [В чем заключаются преимущества технологии сервлетов над CGI (Common Gateway Interface)?](servlets.md#В-чем-заключаются-преимущества-технологии-сервлетов-над-cgi-common-gateway-interface) @@ -758,5 +774,68 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) +## Apache Kafka + +* [Что такое Apache Kafka?](kafka.md#что-такое-apache-kafka) +* [Основные компоненты Kafka](kafka.md#основные-компоненты-kafka) + +**Архитектура компонентов** + +* Topic + * [Архитектура топика](kafka.md#архитектура-топика) + * [Настройки топика Kafka](kafka.md#настройки-топика-kafka) +* Broker + * [Архитектура брокера](kafka.md#архитектура-брокера) + * [Настройки брокера Kafka](kafka.md#настройки-брокера-kafka) +* Producer + * [Архитектура продюсера](kafka.md#архитектура-продюсера) + * [Настройки продюсера](kafka.md#настройки-продюсера) + * [Пример конфигурации Kafka Producer](kafka.md#пример-конфигурации-kafka-producer) +* Consumer + * [Архитектура консюмера](kafka.md#архитектура-консюмера) + * [Настройки консюмера](kafka.md#настройки-консюмера) + * [Пример конфигурации Kafka Consumer](kafka.md#пример-конфигурации-kafka-consumer) + +**Kafka API** + +* [Основные API Kafka](kafka.md#основные-api-kafka) +* [Какова роль Producer API?](kafka.md#какова-роль-producer-api) +* [Какова роль Consumer API?](kafka.md#какова-роль-consumer-api) +* [Какова роль Connector API?](kafka.md#какова-роль-connector-api) +* [Какова роль Streams API?](kafka.md#какова-роль-streams-api) +* [Какова роль Transactions API?](kafka.md#какова-роль-transactions-api) +* [Какова роль Quota API?](kafka.md#какова-роль-quota-api) +* [Какова роль AdminClient API?](kafka.md#какова-роль-AdminClient-api) + +**Kafka Consumer** + +* [Для чего нужен координатор группы?](kafka.md#для-чего-нужен-координатор-группы) +* [Для чего нужен Consumer heartbeat thread?](kafka.md#для-чего-нужен-consumer-heartbeat-thread) +* [Как Kafka обрабатывает сообщения?](kafka.md#как-kafka-обрабатывает-сообщения) +* [Как Kafka обрабатывает задержку консюмера?](kafka.md#как-kafka-обрабатывает-задержку-консюмера) +* [Для чего нужны методы subscribe() и poll()?](kafka.md#для-чего-нужны-методы-subscribe-и-poll) +* [Для чего нужен метод position()?](kafka.md#для-чего-нужен-метод-position) +* [Для чего нужны методы commitSync() и commitAsync()?](kafka.md#для-чего-нужны-методы-commitsync-и-commitasync) + +**Другие вопросы** + +* [Для чего нужен идемпотентный продюсер?](kafka.md#для-чего-нужен-идемпотентный-продюсер) +* [Для чего нужен интерфейс Partitioner?](kafka.md#для-чего-нужен-интерфейс-partitioner) +* [Для чего нужен Broker log cleaner thread?](kafka.md#для-чего-нужен-broker-log-cleaner-thread) +* [Для чего нужен Kafka Mirror Maker?](kafka.md#для-чего-нужен-kafka-mirror-maker) +* [Для чего нужна Schema Registry?](kafka.md#для-чего-нужна-schema-registry) +* [Для чего нужен Streams DSL?](kafka.md#для-чего-нужен-streams-dsl) +* [Как Kafka обеспечивает версионирование сообщений?](kafka.md#как-kafka-обеспечивает-версионирование-сообщений) +* [Как потребители получают сообщения от брокера?](kafka.md#как-потребители-получают-сообщения-от-брокера) + +**Сравнение с другими компонентами и системами** + +* [В чем разница между Kafka Consumer и Kafka Stream?](kafka.md#в-чем-разница-между-kafka-consumer-и-kafka-stream) +* [В чем разница между Kafka Streams и Apache Flink?](kafka.md#в-чем-разница-между-kafka-streams-и-apache-flink) +* [В чем разница между Kafka и Flume?](kafka.md#в-чем-разница-между-kafka-и-flume) +* [В чем разница между Kafka и RabbitMQ?](kafka.md#в-чем-разница-между-kafka-и-rabbitmq) + +[к оглавлению](#Вопросы-для-собеседования-на-java-developer) + ## Источники + [Вопросы на собеседование Junior Java Developer](https://jsehelper.blogspot.ru) diff --git a/kafka.md b/kafka.md new file mode 100644 index 0000000..c579cbf --- /dev/null +++ b/kafka.md @@ -0,0 +1,1420 @@ +[Вопросы для собеседования](README.md) + +# Apache Kafka +* [Что такое Apache Kafka?](#что-такое-apache-kafka) +* [Основные компоненты Kafka](#основные-компоненты-kafka) + +**Архитектура компонентов** + +* Topic + * [Архитектура топика](#архитектура-топика) + * [Настройки топика Kafka](#настройки-топика-kafka) +* Broker + * [Архитектура брокера](#архитектура-брокера) + * [Настройки брокера Kafka](#настройки-брокера-kafka) +* Producer + * [Архитектура продюсера](#архитектура-продюсера) + * [Настройки продюсера](#настройки-продюсера) + * [Пример конфигурации Kafka Producer](#пример-конфигурации-kafka-producer) +* Consumer + * [Архитектура консюмера](#архитектура-консюмера) + * [Настройки консюмера](#настройки-консюмера) + * [Пример конфигурации Kafka Consumer](#пример-конфигурации-kafka-consumer) + +**Kafka API** + +* [Основные API Kafka](#основные-api-kafka) +* [Какова роль Producer API?](#какова-роль-producer-api) +* [Какова роль Consumer API?](#какова-роль-consumer-api) +* [Какова роль Connector API?](#какова-роль-connector-api) +* [Какова роль Streams API?](#какова-роль-streams-api) +* [Какова роль Transactions API?](#какова-роль-transactions-api) +* [Какова роль Quota API?](#какова-роль-quota-api) +* [Какова роль AdminClient API?](#какова-роль-AdminClient-api) + +**Kafka Consumer** + +* [Для чего нужен координатор группы?](#для-чего-нужен-координатор-группы) +* [Для чего нужен Consumer heartbeat thread?](#для-чего-нужен-consumer-heartbeat-thread) +* [Как Kafka обрабатывает сообщения?](#как-kafka-обрабатывает-сообщения) +* [Как Kafka обрабатывает задержку консюмера?](#как-kafka-обрабатывает-задержку-консюмера) +* [Для чего нужны методы subscribe() и poll()?](#для-чего-нужны-методы-subscribe-и-poll) +* [Для чего нужен метод position()?](#для-чего-нужен-метод-position) +* [Для чего нужны методы commitSync() и commitAsync()?](#для-чего-нужны-методы-commitsync-и-commitasync) + +**Другие вопросы** + +* [Для чего нужен идемпотентный продюсер?](#для-чего-нужен-идемпотентный-продюсер) +* [Для чего нужен интерфейс Partitioner?](#для-чего-нужен-интерфейс-partitioner) +* [Для чего нужен Broker log cleaner thread?](#для-чего-нужен-broker-log-cleaner-thread) +* [Для чего нужен Kafka Mirror Maker?](#для-чего-нужен-kafka-mirror-maker) +* [Для чего нужна Schema Registry?](#для-чего-нужна-schema-registry) +* [Для чего нужен Streams DSL?](#для-чего-нужен-streams-dsl) +* [Как Kafka обеспечивает версионирование сообщений?](#как-kafka-обеспечивает-версионирование-сообщений) +* [Как потребители получают сообщения от брокера?](#как-потребители-получают-сообщения-от-брокера) + +**Сравнение с другими компонентами и системами** + +* [В чем разница между Kafka Consumer и Kafka Stream?](#в-чем-разница-между-kafka-consumer-и-kafka-stream) +* [В чем разница между Kafka Streams и Apache Flink?](#в-чем-разница-между-kafka-streams-и-apache-flink) +* [В чем разница между Kafka и Flume?](#в-чем-разница-между-kafka-и-flume) +* [В чем разница между Kafka и RabbitMQ?](#в-чем-разница-между-kafka-и-rabbitmq) + + +## Что такое Apache Kafka? + +Это распределённая система с открытым исходным кодом, разработанная для высокоскоростной передачи больших объёмов данных +с минимальной задержкой. + +### Преимущества + +* Персистентность данных +* Высокая производительность +* Независимость пайплайнов обработки +* Возможность просмотреть историю записей заново +* Гибкость в использовании + +### Когда использовать + +* λ-архитектура или k-архитектура +* Стриминг больших данных +* Много клиентов (producer и consumer) +* Требуется кратное масштабирование + +### Чего в Kafka нет из коробки + +* Это не брокер сообщений +* Отложенные сообщения +* DLQ +* AMQP / MQTT +* TTL на сообщение +* Очереди с приоритетами + +[к оглавлению](#apache-kafka) + +## Основные компоненты Kafka + +* **Producer (Производитель)** — приложение, которое публикует сообщения в топики Kafka +* **Consumer (Потребитель)** — приложение, которое подписывается на топики и читает сообщения +* **Broker (Брокер)** — сервер Kafka, который принимает, хранит и распределяет сообщения. В кластере Kafka может быть несколько брокеров +* **Topic (Топик)** — логическое разделение, по которому организуются данные. Производители отправляют сообщения в топики, а потребители читают из них +* **Partition (Раздел)** — каждый топик разделён на партиции для параллельной обработки. Сообщения в партициях упорядочены +* **Zookeeper** — сервис, используемый Kafka для управления состоянием кластера и координации брокеров. +Однако в новых версиях Kafka отказывается от Zookeeper в пользу собственного механизма метаданных KRaft (Kafka Raft). +Это новая внутренняя архитектура метаданных Kafka, которая устраняет зависимость от Zookeeper. Она основана на Raft-консенсусе, +позволяя Kafka брокерам самостоятельно управлять метаданными и координировать взаимодействие между собой. + +[к оглавлению](#apache-kafka) + +## Архитектура топика + +* **Топик разбит на партиции** — сообщения в топике распределяются по партициям для более эффективной параллельной обработки и хранения +* **Партиции хранятся на диске** — Kafka сохраняет данные на диск, что позволяет долговременно хранить сообщения +* **Партиции делятся на сегменты** — сегмент представляет собой обычный файл на диске, сегменты делятся на пассивные и активный. + Запись происходит в активный сегмент +* **Данные удаляются либо по времени, либо по размеру**. Удаление происходит посегментно, с самого старого сегмента + * **retention.bytes** - по максимальному размеру + * **retention.ms** - по времени +* **Сообщение можно быстро найти по его Offset** — каждому сообщению в партиции присваивается уникальный смещающий индекс (offset), по которому можно легко найти сообщение + +[к оглавлению](#apache-kafka) + +## Настройки топика Kafka + +### Репликация + +* `replication.factor` + * **Описание**: Количество реплик для каждой партиции топика + * **Пример**: `replication.factor=3` +* `min.insync.replicas` + * **Описание**: Минимальное количество синхронизированных реплик + * **Пример**: `min.insync.replicas=2` + +### Хранение данных + +* `retention.ms` + * **Описание**: Время хранения сообщений в топике в миллисекундах + * **Пример**: `retention.ms=604800000` (7 дней) +* `retention.bytes` + * **Описание**: Максимальный объём данных в топике, после чего старые сообщения удаляются + * **Пример**: `retention.bytes=10737418240` (10 GB) +* `segment.bytes` + * **Описание**: Размер сегмента логов топика + * **Пример**: `segment.bytes=1073741824` (1 GB) + +### Политики очистки + +* `cleanup.policy` + * **Описание**: Как Kafka обрабатывает старые сообщения + * **Значения**: `delete`, `compact` + * **Пример**: `cleanup.policy=delete` + +### Партиции + +* `num.partitions` + * **Описание**: Количество партиций в топике + * **Пример**: `num.partitions=3` + +[к оглавлению](#apache-kafka) + +## Архитектура брокера + +* **У каждой партиции свой лидер** — в Kafka для каждой партиции в топике назначается лидер-брокер, который отвечает + за запись и чтение данных +* **Сообщения пишутся в лидера** — производители отправляют сообщения напрямую в брокер-лидер партиции +* **Данные реплицируются между брокерами** — для обеспечения отказоустойчивости Kafka реплицирует данные партиций на + другие брокеры, которые становятся репликами +* **Автоматический фейловер лидера** — в случае сбоя брокера-лидера Kafka автоматически назначает новый лидер из числа + реплик, обеспечивая бесшовную работу системы + +[к оглавлению](#apache-kafka) + +## Настройки брокера Kafka + +### Репликация и консистентность + +* `min.insync.replicas` + * **Описание**: Минимальное количество синхронизированных реплик для подтверждения записи + * **Пример**: `min.insync.replicas=2` +* `unclean.leader.election.enable` + * **Описание**: Разрешает выбор лидера из неактуальных реплик, если нет синхронизированных реплик + * **Пример**: `unclean.leader.election.enable=false` + +### Логирование и хранение данных + +* `log.dirs` + * **Описание**: Директория на диске, где хранятся логи партиций + * **Пример**: `log.dirs=/var/lib/kafka/logs` +* `log.retention.hours` + * **Описание**: Максимальное время хранения данных в логах + * **Пример**: `log.retention.hours=168` (7 дней) +* `log.segment.bytes` + * **Описание**: Максимальный размер сегмента лога, после чего создаётся новый + * **Пример**: `log.segment.bytes=1073741824` (1 GB) + +### Производительность и задержки + +* `num.network.threads` + * **Описание**: Количество потоков для обработки сетевых запросов + * **Пример**: `num.network.threads=3` +* `num.io.threads` + * **Описание**: Количество потоков для ввода-вывода + * **Пример**: `num.io.threads=8` +* `socket.send.buffer.bytes` + * **Описание**: Размер буфера для отправки данных по сети + * **Пример**: `socket.send.buffer.bytes=102400` + +### Управление сообщениями + +* `message.max.bytes` + * **Описание**: Максимальный размер сообщения, которое брокер может принять + * **Пример**: `message.max.bytes=1048576` (1 MB) +* `replica.fetch.max.bytes` + * **Описание**: Максимальный размер данных для запроса реплики + * **Пример**: `replica.fetch.max.bytes=1048576` (1 MB) + +### Безопасность + +* `ssl.keystore.location` + * **Описание**: Путь к хранилищу ключей SSL + * **Пример**: `ssl.keystore.location=/var/private/ssl/kafka.keystore.jks` +* `ssl.truststore.location` + * **Описание**: Путь к хранилищу доверенных сертификатов + * **Пример**: `ssl.truststore.location=/var/private/ssl/kafka.truststore.jks` + +[к оглавлению](#apache-kafka) + +## Архитектура продюсера + +* **Создание сообщения (Record)**: Продюсер формирует сообщение, содержащее ключ (необязательный), значение и метаданные, + такие как время отправки. Сообщение отправляется в топик (Topic), который состоит из одной или нескольких партиций +* **Выбор партиции**: Если ключ сообщения указан, Kafka использует его для хеширования и определения, в какую партицию + записать сообщение (сообщения с одинаковым ключом попадают в одну и ту же партицию). Если ключа нет, Kafka распределяет + сообщения по партициям с помощью round-robin или по другим правилам +* **Отправка сообщений в буфер (Batching)**: Для повышения производительности продюсер Kafka не отправляет каждое сообщение + по отдельности, а группирует несколько сообщений в пакеты (batching), прежде чем отправить их брокеру. Это снижает + сетевые задержки и нагрузку на брокера +* **Сжатие (Compression)**: Для уменьшения объёма передаваемых данных продюсер может сжимать сообщения с использованием + таких алгоритмов, как GZIP, Snappy или LZ4. Сжатие снижает нагрузку на сеть и хранение, но добавляет небольшие накладные + расходы на процессор +* **Асинхронная отправка**: Продюсер отправляет пакеты сообщений асинхронно. Это означает, что сообщения записываются в + буфер памяти и отправляются брокеру, не ожидая завершения предыдущих операций. Это повышает пропускную способность +* **Подтверждения (Acknowledgments)**: Kafka позволяет настраивать уровень подтверждений от брокеров +* **Ретрай и идемпотентность**: Если отправка сообщения не удалась, продюсер может повторить попытку отправки (ретрай). + Также можно включить идемпотентный режим продюсера, что предотвращает повторную отправку одного и того же сообщения в + случае сбоя, обеспечивая отправку уникального сообщения один раз +* **Error handling**: Продюсер обрабатывает ошибки при отправке сообщений. В зависимости от настроек продюсер может + попытаться переотправить сообщение или сообщить о проблеме через callback + +### Резюме + +* Продюсер выбирает партицию для сообщения +* Продюсер выбирает уровень гарантии доставки +* В продюсере можно тюнить производительность + +[к оглавлению](#apache-kafka) + +## Настройки продюсера + +### Bootstrap-серверы (`bootstrap.servers`) + +* **Описание**: Указывает адреса брокеров Kafka, к которым продюсер должен подключаться для отправки сообщений +* **Пример**: `bootstrap.servers: localhost:9092,localhost:9093` +* **Зачем это нужно**: Kafka продюсер использует эти брокеры для получения метаданных о кластере (например, информация о топиках и партициях). Эти брокеры служат точками входа в кластер Kafka. + +### Сериализация ключа и значения + +Продюсер должен преобразовывать (сериализовать) данные в байтовый формат перед отправкой в Kafka + +* **Ключевая настройка для сериализации ключа:** + * `key.serializer` + * Пример: `key.serializer: org.apache.kafka.common.serialization.StringSerializer` +* **Ключевая настройка для сериализации значения:** + * `value.serializer` + * Пример: `value.serializer: org.apache.kafka.common.serialization.StringSerializer` + +**Варианты сериализаторов:** +* `StringSerializer` для строк +* `ByteArraySerializer` для массива байтов +* `LongSerializer` для чисел +* Также можно реализовать свои собственные сериализаторы + +### Отправка сообщений в буфер + +Продюсер Kafka отправляет сообщения асинхронно, и для этого используется буферизация сообщений + +* **batch.size**: Размер одного пакета (batch), который продюсер отправляет брокеру + * **Описание**: Определяет количество байтов сообщений, которые могут быть буферизованы в одном пакете перед отправкой брокеру + * **Пример**: `"batch.size": 16384` (16 KB) + * **Зачем это нужно**: Большие пакеты могут повысить производительность, но могут увеличить задержки +* **linger.ms**: Максимальное время ожидания перед отправкой пакета + * **Описание**: Продюсер может немного подождать, пока буфер накопит сообщения, чтобы отправить больше данных за один раз + * **Пример**: `linger.ms: 5` (время ожидания 5 мс) + * **Зачем это нужно**: Позволяет продюсеру собирать больше сообщений в пакете перед отправкой, что может улучшить эффективность использования сети +* **buffer.memory**: Размер выделенной памяти для буферизации сообщений + * **Описание**: Общий объем памяти, который продюсер может использовать для хранения сообщений, ожидающих отправки + * **Пример**: `buffer.memory: 33554432` (32 MB) + * **Зачем это нужно**: Если буфер заполняется, продюсер приостанавливает отправку сообщений, пока буфер не освободится + +### Сжатие сообщений + +Продюсер может сжимать сообщения для уменьшения объема передаваемых данных + +* **compression.type** + * **Описание**: Указывает тип сжатия для сообщений + * **Пример**: `compression.type: gzip` (варианты: none, gzip, snappy, lz4, zstd) + * **Зачем это нужно**: Сжатие уменьшает объем данных, передаваемых по сети, что может снизить нагрузку на сеть и хранилище, + особенно при больших объемах сообщений. Однако это может потребовать дополнительных ресурсов на сжатие/разжатие + +### Распределение сообщений по партициям (партицирование) + +* **partitioner.class** + * **Описание**: определяет логику, по которой продюсер выбирает партицию для каждого сообщения + * **Примеры**: + * **если настройка не задана**, по умолчанию используется `DefaultPartitioner` , который может распределять сообщения по партициям + равномерно или на основе ключа сообщения + * `partitioner.class: o.a.k.clients.producer.RoundRobinPartitioner` использует метод Round Robin для распределения сообщений + * `partitioner.class: o.a.k.clients.producer.UniformStickyPartitioner` равномерно отправляет сообщения, привязываясь + к партиции на короткий промежуток времени, чтобы уменьшить нагрузку на брокеры + +### Подтверждения (acks) + +Настройка определяет, как много брокеров должны подтвердить получение сообщения перед тем, как продюсер будет считать его +успешно отправленным + +* **acks** + * **Описание**: Определяет количество подтверждений от брокеров + * **Значения**: + * `0`: Продюсер не ждёт подтверждений (самая быстрая отправка, но высокий риск потери сообщений) + * `1`: Продюсер ждёт подтверждения от лидера партиции + * `all` (или `-1`): Продюсер ждёт подтверждений от всех реплик (наибольшая надежность, но увеличенные задержки) + * **Пример**: `acks: all` + * **Зачем это нужно**: Позволяет выбрать баланс между скоростью и надежностью отправки данных. + +### Дополнительные важные настройки + +* **Количество повторных попыток (retries):** + * **Описание**: Определяет, сколько раз продюсер должен попытаться отправить сообщение при неудаче + * **Пример**: `retries: 3` + * **Зачем это нужно**: Если произошёл временный сбой, продюсер может попытаться повторить отправку сообщений, что + увеличивает шанс доставки +* **Идемпотентность продюсера (enable.idempotence):** + * **Описание**: Включение идемпотентного режима, что предотвращает дублирование сообщений при сбоях + * **Пример**: `enable.idempotence: true` + * **Зачем это нужно**: Гарантирует, что каждое сообщение будет доставлено ровно один раз +* **Максимальный размер сообщения (max.request.size):** + * **Описание**: Максимальный размер сообщения, которое продюсер может отправить брокеру + * **Пример**: `max.request.size: 1048576` (1 MB) + * **Зачем это нужно**: Ограничивает размер сообщений, которые могут быть отправлены, чтобы избежать перегрузки сети и брокеров. +* **Таймаут ожидания подтверждений (request.timeout.ms):** + * **Описание**: Максимальное время ожидания подтверждения от брокера + * **Пример**: `request.timeout.ms: 30000` (30 секунд) + * **Зачем это нужно**: Помогает избежать бесконечного ожидания ответа от брокера в случае его сбоя + +[к оглавлению](#apache-kafka) + +## Пример конфигурации Kafka Producer + +```java +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import java.util.Properties; + +public class KafkaStringArrayProducer { + + public static void main(String[] args) { + // Настройки Kafka Producer + Properties props = new Properties(); + props.put("bootstrap.servers", "localhost:9092"); + props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); + props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); + + // Создание Kafka Producer + KafkaProducer producer = new KafkaProducer<>(props); + + String key = "user123"; + String[] value = {"message1", "message2", "message3"}; + + // Создание записи и добавление заголовков + ProducerRecord record = new ProducerRecord<>("my_topic", key, value); + record.headers().add("traceId", "someTraceId"); + + // Отправка сообщения в Kafka + producer.send(record, (metadata, exception) -> { + if (exception != null) { + System.out.println("Ошибка при отправке сообщения: " + exception.getMessage()); + } else { + System.out.println("Сообщение отправлено в топик " + metadata.topic() + " с партицией " + metadata.partition()); + } + }); + + producer.close(); + } +} +``` + +```properties +acks=all +retries=3 +compression.type=gzip +``` + +### С использованием Spring Kafka + +```java +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.config.ConcurrentMessageListenerContainer; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.producer.Producer; +import org.springframework.kafka.producer.ProducerRecord; + +import java.util.HashMap; +import java.util.Map; + +@EnableKafka +@Configuration +public class KafkaProducerConfig { + + @Autowired + private KafkaProperties kafkaProperties; + + @Bean + public Map producerConfigs() { + Map props = new HashMap<>(); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getServer()); + props.put(ProducerConfig.CLIENT_ID_CONFIG, kafkaProperties.getProducerId()); + props.put( + ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, + "com.example.configuration.kafka.KafkaProducerLoggingInterceptor" + ); + + if ("SASL_SSL".equals(kafkaProperties.getSecurityProtocol())) { + props.put("ssl.truststore.location", kafkaProperties.getSslTrustStoreLocation()); + props.put("ssl.truststore.password", kafkaProperties.getSslTrustStorePassword()); + props.put("ssl.truststore.type", kafkaProperties.getSslTrustStoreType()); + props.put("ssl.keystore.type", kafkaProperties.getSslKeyStoreType()); + + props.put("sasl.mechanism", kafkaProperties.getSaslMechanism()); + props.put("security.protocol", kafkaProperties.getSecurityProtocol()); + props.put("sasl.jaas.config", kafkaProperties.getJaasConfigCompiled()); + } + + return props; + } + + @Bean + public ProducerFactory producerFactory() { + var stringSerializerKey = new StringSerializer(); + stringSerializerKey.configure(Map.of("key.serializer.encoding", "UTF-8"), true); + stringSerializerKey.configure(Map.of("serializer.encoding", "UTF-8"), true); + + var stringSerializerValue = new StringSerializer(); + stringSerializerValue.configure(Map.of("value.serializer.encoding", "UTF-8"), false); + stringSerializerValue.configure(Map.of("serializer.encoding", "UTF-8"), false); + + return new DefaultKafkaProducerFactory<>(producerConfigs(), stringSerializerKey, stringSerializerValue); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } +} +``` + +```java +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +@Service +public class KafkaProducerService { + + private final KafkaTemplate kafkaTemplate; + + public KafkaProducerService(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + public void sendMessage(String message, String key, String topic) { + try { + log.info("Sending message {}", data); + kafkaTemplate.send(topic, key, message); + log.info("Successfully send message {}", data); + } catch (Exception ex) { + log.error("Failed send message to {} topic by key {}", key, topic); + throw ex; + } + } +} +``` + +```java +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/kafka") +public class KafkaController { + + @Autowired + private KafkaProducerService kafkaProducerService; + + @PostMapping("/send") + public String sendMessage(@RequestParam String message, @RequestParam String key, @RequestParam String topic) { + kafkaProducerService.sendMessage(message, key, topic); + return "Message sent to Kafka!"; + } +} +``` + +### С использованием Spring Cloud Stream + +```yaml +spring: + cloud: + stream: + bindings: + output: + destination: my_topic + kafka: + binder: + brokers: localhost:9092 +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.messaging.Source; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Service; + +@Service +@EnableBinding(Source.class) // Подключение к каналу сообщений +public class KafkaStreamProducer { + + private final Source source; + + public KafkaStreamProducer(Source source) { + this.source = source; + } + + public void sendMessage(String message) { + Message msg = MessageBuilder.withPayload(message).build(); + source.output().send(msg); // Отправка сообщения в Kafka + } +} +``` + +```java +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/kafka-stream") +public class KafkaStreamController { + + @Autowired + private KafkaStreamProducer kafkaStreamProducer; + + @PostMapping("/send") + public String sendMessage(@RequestParam String message) { + kafkaStreamProducer.sendMessage(message); + return "Message sent to Kafka via Spring Cloud Stream!"; + } +} +``` + +[к оглавлению](#apache-kafka) + +## Архитектура консюмера + +Потребители используют **Kafka Consumer API** для взаимодействия с брокерами Kafka. Они получают сообщения и обрабатывают +их согласно своей логике. Потребители могут быть объединены в группы **Consumer Groups**. + +### Резюме + +* "Smart" консюмер +* Консюмер опрашивает кафку +* Консюмер отвечает за гарантию обработки +* Автоматические фейловер в консюмер-группе +* Независимая обработка разными консюмер-группе + +### Компоненты + +#### Consumer Group + +Kafka использует концепцию Consumer Groups, что позволяет нескольким потребителям работать вместе, чтобы параллельно +обрабатывать данные из топиков. Каждый потребитель в группе обрабатывает только часть данных из топика, обеспечивая масштабируемость и балансировку нагрузки. + +* Все сообщения из одного Kafka Topic делятся между всеми потребителями в группе +* Если в группе несколько потребителей, Kafka гарантирует, что каждая партиция топика будет обрабатываться только одним потребителем +* В случае если один из потребителей выходит из строя, его партиции автоматически перераспределяются между оставшимися активными потребителями + +#### Offset (Смещение) + +Потребитель отслеживает offset каждой партиции, чтобы понимать, с какого сообщения продолжать чтение. Смещение — это +уникальный идентификатор каждого сообщения в партиции. + +Потребители могут хранить offset в Kafka или вне её (например, в базе данных или файловой системе). Если потребитель +отключается, он может возобновить обработку с того места, где остановился, прочитав сохранённый offset. + +#### Poll (Опрос) + +Потребители используют метод poll() для опроса Kafka на наличие новых сообщений. Это асинхронный процесс, и Kafka будет +отправлять потребителю доступные сообщения по мере их поступления. + +* Потребитель может указывать тайм-аут, после которого метод poll() вернёт пустой результат, если сообщений нет. +* Потребитель должен обрабатывать сообщения, а затем снова опрашивать Kafka для получения новых данных. + +### Процесс работы + +1. **Инициализация**: Потребитель подключается к Kafka-брокерам и присоединяется к consumer group. Он получает информацию о партиции топика, который будет читать. +2. **Подписка на топик**: Потребитель подписывается на определённые топики с помощью метода `subscribe()`. +3. **Опрос**: Потребитель вызывает метод `poll()` для получения новых сообщений. Если в очереди есть сообщения, они передаются потребителю для обработки. +4. **Обработка сообщений**: Потребитель обрабатывает сообщения, извлекая полезную информацию из каждого. +5. **Подтверждение обработки**: После обработки сообщения потребитель подтверждает обработку с помощью `commit()`. + Это обновляет **offset**, позволяя потребителю продолжить чтение с места, на котором остановился. +6. **Обработка ошибок**: В случае ошибки потребитель может решить, как повторить обработку сообщения + (например, с использованием механизма повторных попыток). +7. **Завершение работы**: Когда потребитель завершает обработку, он выходит из consumer group и может закрыть соединение с Kafka. + +[к оглавлению](#apache-kafka) + +## Настройки консюмера + +* **bootstrap.servers** — список брокеров, к которым будет подключаться потребитель +* **group.id** — идентификатор группы потребителей +* **auto.offset.reset** — настройка поведения при отсутствии offset (`earliest` для чтения с самого начала или `latest` для чтения с конца) +* **enable.auto.commit** — указывает, должен ли потребитель автоматически коммитить offset. Если `false`, потребитель должен делать это вручную +* **auto.commit.interval.ms** — определяет интервал времени между автоматическими коммитами offset сообщений, если включена автоматическая фиксация +* **max.poll.records** — максимальное количество сообщений, которые потребитель будет получать за один вызов `poll()` +* **session.timeout.ms** — максимальное время без общения с Kafka перед тем, как потребитель считается недоступным +* **client.rack** — используется для указания серверной стойки или дата-центра. Это особенно важно в случае, если у вас + есть распределённая инфраструктура Kafka с несколькими стойками или дата-центрами, где сообщения могут быть реплицированы + между разными физическими местоположениями (например, несколькими дата-центрами). + +### Что такое Rack в контексте Kafka? + +**Rack** — это метка, которая идентифицирует физическое местоположение брокеров Kafka. В Kafka можно задать rack для каждого брокера +с помощью параметра `broker.rack`, чтобы управлять репликацией данных, предпочтительно размещая реплики на разных физических машинах или в разных дата-центрах. + +**Преимущества использования client.rack** + +* **Снижение задержек**: Kafka будет предпочитать, чтобы данные попадали в тот же rack, где находится клиент, что уменьшает время отклика +* **Повышенная отказоустойчивость**: С правильной настройкой client.rack и broker.rack можно улучшить отказоустойчивость + за счет размещения реплик в разных физически удаленных местах +* **Лучшее использование ресурсов**: Правильное распределение нагрузки по rack помогает избежать перегрузки одного физического местоположения + +[к оглавлению](#apache-kafka) + +## Пример конфигурации Kafka Consumer + +```java +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +public class KafkaConsumerExample { + + public static void main(String[] args) { + String bootstrapServers = "localhost:9092"; + String groupId = "my-consumer-group"; + String topic = "my-topic"; + + // Настройки Consumer + Map consumerConfigs = new HashMap<>(); + consumerConfigs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + consumerConfigs.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + consumerConfigs.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + consumerConfigs.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + consumerConfigs.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + + // Создание Consumer + KafkaConsumer consumer = new KafkaConsumer<>(consumerConfigs); + + // Подписка на тему + consumer.subscribe(Collections.singletonList(topic)); + + try { + // Чтение сообщений из Kafka + while (true) { + var records = consumer.poll(Duration.ofSeconds(1)); + records.forEach(record -> System.out.println("Received message: " + record.value())); + } + } finally { + consumer.close(); + } + } +} +``` + +**At least once** + +Чтобы гарантировать обработку сообщений хотя бы один раз, нужно коммитить после обработки. + +```java +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +public class KafkaConsumerAtLeastOnce { + + public static void main(String[] args) { + try { + // Чтение сообщений + while (true) { + var records = consumer.poll(Duration.ofSeconds(1)); // Ожидание 1 секунду для получения сообщений + process(records); + consumer.commitAsync(); // Commit после обработки + } + } finally { + consumer.close(); // Закрытие consumer + } + } +} +``` + +**At most once** + +Чтобы гарантировать обработку сообщений не более одного раза, нужно коммитить до обработки или включить авто-подтверждение смещений +`enable.auto.commit=true`. + +```java +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +public class KafkaConsumerAtLeastOnce { + + public static void main(String[] args) { + try { + // Чтение сообщений + while (true) { + var records = consumer.poll(Duration.ofSeconds(1)); // Ожидание 1 секунду для получения сообщений + consumer.commitAsync(); // Commit перед обработкой + process(records); + } + } finally { + consumer.close(); // Закрытие consumer + } + } +} +``` + +### С использованием Spring Kafka + +```java +@EnableKafka +@Configuration +public class KafkaConsumerConfig { + + @Autowired + private KafkaProperties kafkaProperties; + + @Bean + public ConsumerFactory consumerFactory() { + return new DefaultKafkaConsumerFactory<>(consumerConfigs()); + } + + @Bean + public Map consumerConfigs() { + Map configs = new HashMap<>(); + configs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getServer()); + configs.put(ConsumerConfig.GROUP_ID_CONFIG, kafkaProperties.getConsumerGroupId()); + configs.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + configs.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + return configs; + } + + @Bean + public KafkaListenerContainerFactory> kafkaListenerContainerFactory() { + ConcurrentMessageListenerContainerFactory factory = new ConcurrentMessageListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory()); + return factory; + } +} +``` + +```java +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Service; + +@Service +public class KafkaConsumer { + + @KafkaListener(topics = "my_topic", groupId = "group_id") + public void listen(@Payload String message, + @Header("traceId") String traceId, + @Header("correlationId") String correlationId) { + System.out.println("Received message: " + message); + System.out.println("Trace ID: " + traceId); + System.out.println("Correlation ID: " + correlationId); + } +} +``` + +**At least once** + +```yaml +spring: + kafka: + consumer: + enable-auto-commit: false # Отключение авто-commit + auto-offset-reset: earliest # Начинать чтение с самого начала (если нет смещения) + group-id: my-consumer-group + max-poll-records: 500 # Максимальное количество сообщений для обработки за один раз + listener: + ack-mode: manual # Ручное подтверждение +``` + +```java +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.listener.MessageListener; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.listener.config.DefaultMessageListenerContainer; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.listener.MessageListener; +import org.springframework.kafka.listener.MessageListenerContainer; + +@EnableKafka +public class AtLeastOnceConsumer { + + @KafkaListener(topics = "my-topic", groupId = "my-consumer-group") + public void listen(String message, Acknowledgment acknowledgment) { + System.out.println("Received message: " + message); + // Обработка сообщения + // Подтверждение смещения вручную после успешной обработки + acknowledgment.acknowledge(); + } +} +``` + +**At most once** + +```yaml +spring: + kafka: + consumer: + enable-auto-commit: true # Включение авто-commit + group-id: my-consumer-group + auto-offset-reset: earliest # Начинать чтение с самого начала + max-poll-records: 100 # Максимальное количество сообщений для обработки за один раз +``` + +```java +import org.springframework.kafka.annotation.KafkaListener; + +public class AtMostOnceConsumer { + + @KafkaListener(topics = "my-topic", groupId = "my-consumer-group") + public void listen(String message) { + System.out.println("Received message: " + message); + // Обработка сообщения... + // Смещение будет автоматически зафиксировано после получения сообщения + } +} +``` + +### С использованием Spring Cloud Stream + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + kafka: + binder: + brokers: localhost:9092 + auto-create-topics: false +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Service; + +@Service +@EnableBinding(KafkaProcessor.class) // Указывает на интерфейс, с которым связывается этот сервис +public class KafkaConsumerService { + + // Метод будет слушать сообщения из указанного канала + @StreamListener("input") + public void handle(@Payload String message) { + System.out.println("Received message: " + message); + } +} +``` + +```java +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.messaging.SubscribableChannel; + +public interface KafkaProcessor { + + @Input("input") // Имя канала, которое мы используем в application.yml + SubscribableChannel input(); +} +``` + +**At least once** + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + consumer: + ackMode: manual # Ручное подтверждение + maxAttempts: 3 # Максимальное количество попыток +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; + +@Component +@EnableBinding(Sink.class) // Sink - это интерфейс, предоставляющий Binding для входных сообщений +public class AtLeastOnceConsumer { + + @StreamListener(Sink.INPUT) + public void handleMessage(Message message, @Header(name = "kafka_offset") String offset) { + // Обработка сообщения + System.out.println("Received message: " + message.getPayload()); + // После успешной обработки подтверждаем сообщение + // Spring Cloud Stream автоматически подтвердит сообщение после завершения метода + // благодаря ackMode=manual и настроенному acknowledgment + } +} +``` + +**At most once** + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + consumer: + ackMode: batch # Автоматическое подтверждение после пакета сообщений +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Component; + +@Component +@EnableBinding(Sink.class) +public class AtMostOnceConsumer { + + @StreamListener(Sink.INPUT) + public void handleMessage(Message message) { + // Обработка сообщения + System.out.println("Received message: " + message.getPayload()); + // Смещение будет автоматически зафиксировано после получения сообщения + } +} +``` + +**Mostly Once** + +Это гибридный режим, который стремится быть чем-то средним между At least once и At most once. Он предполагает, что сообщения +будут доставлены обычно один раз, но иногда, в случае сбоев, может быть обработано больше одного раза. Для реализации +такого режима в Spring Cloud Stream потребуется дополнительная логика, например, фильтрация дублированных сообщений или +использование уникальных идентификаторов сообщений. + +В рамках Spring Cloud Stream, можно обработать Mostly Once с использованием уникальных идентификаторов сообщений или +кеширования состояния, чтобы отфильтровать повторно обработанные сообщения. + +```yaml +spring: + cloud: + stream: + bindings: + input: + destination: my-topic + group: my-consumer-group + content-type: application/json + consumer: + ackMode: manual # Ручное подтверждение + maxAttempts: 3 # Максимальное количество попыток +``` + +```java +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.Set; + +@Component +@EnableBinding(Sink.class) +public class MostlyOnceConsumer { + + private Set processedMessageIds = new HashSet<>(); + + @StreamListener(Sink.INPUT) + public void handleMessage(Message message, @Header("messageId") String messageId) { + if (processedMessageIds.contains(messageId)) { + System.out.println("Duplicate message: " + messageId); + return; // Пропускаем дублированное сообщение + } + // Обработка сообщения + System.out.println("Received message: " + message.getPayload()); + // Добавляем идентификатор в обработанные + processedMessageIds.add(messageId); + // После успешной обработки подтверждаем сообщение вручную + // Spring Cloud Stream подтвердит сообщение после выполнения метода + } +} +``` + +[к оглавлению](#apache-kafka) + +## Основные API Kafka + +* Producer API +* Consumer API +* Streams API +* Connector API + +[к оглавлению](#apache-kafka) + +## Какова роль Producer API? + +Используется для публикации потока сообщений в топики Kafka. Он управляет партицированием сообщений, сжатием и балансировкой +нагрузки между несколькими брокерами. Продюсер также отвечает за повторные неудачные попытки публикации и может быть +настроен на различные уровни гарантий доставки. + +[к оглавлению](#apache-kafka) + +## Какова роль Consumer API? + +Обеспечивает механизм для потребления сообщений топиков. Оно позволяет приложениям и микросервисам читать данные, +поступающие в Kafka, и обрабатывать их для дальнейшего использования, будь то хранение, анализ или реактивная обработка. + +[к оглавлению](#apache-kafka) + +## Какова роль Connector API? + +Connector API в Apache Kafka является частью Kafka Connect, которая представляет собой инфраструктуру для интеграции +внешних систем с Kafka. Connector API играет ключевую роль в упрощении процесса подключения различных источников данных +и систем-приемников к Kafka, предоставляя возможность автоматического перемещения данных между ними. + +[к оглавлению](#apache-kafka) + +## Какова роль Streams API? + +Это компонент Apache Kafka, предназначенный для создания приложений и микросервисов, которые обрабатывают потоки данных +в реальном времени. Его основная роль заключается в том, чтобы позволить разработчикам легко обрабатывать и анализировать +данные, поступающие в виде непрерывных потоков из топиков. Kafka Streams API предоставляет высокоуровневый интерфейс для +выполнения таких операций, как фильтрация, агрегация, объединение данных и вычисление оконных функций. + +[к оглавлению](#apache-kafka) + +## Какова роль Transactions API? + +Kafka Transactions API позволяет выполнять атомарные обновления для нескольких топиков. Он включает exactly-once +гарантию для приложений, которые читают данные из одного топика и пишут в другой. Это особенно полезно для приложений потоковой +обработки, которым необходимо гарантировать, что каждое входное событие влияет на выходные данные ровно один раз, даже в случае сбоев. + +[к оглавлению](#apache-kafka) + +## Какова роль Quota API? + +Quota API позволяет настраивать квоты для каждого клиента для ограничения скорости создания или потребления данных, чтобы +один клиент не потреблял слишком много ресурсов брокера. Это помогает обеспечить справедливое распределение ресурсов и +предотвратить сценарии отказа в обслуживании. + +[к оглавлению](#apache-kafka) + +## Какова роль AdminClient API? + +AdminClient API предоставляет операции для управления топиками, брокерами, конфигурацией и другими объектами Kafka. +Его можно использовать для создания, удаления и описания топиков, управления списками ACL, получения информации о кластере и +программного выполнения других административных задач. + +[к оглавлению](#apache-kafka) + +## Kafka Consumer + +## Для чего нужен координатор группы? + +Координатор группы отвечает за управление группами потребителей. Он управляет членством в группах потребителей, назначает +партиции потребителям внутри группы и управляет фиксацией смещения. Когда потребитель присоединяется к группе или покидает ее, +координатор группы запускает перебалансировку для переназначения партиций среди оставшихся потребителей. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Consumer heartbeat thread? + +Consumer Heartbeat Thread отвечает за отправку периодических сигналов брокеру Kafka (в частности, координатору группы). +Эти сигналы указывают на то, что потребитель жив и все еще является частью группы потребителей. Если потребитель не отправляет +данные сигналы в течение настроенного периода, он считается неживым, и координатор группы инициирует перебалансировку +для переназначения его партиций другим потребителям в группе. + +[к оглавлению](#apache-kafka) + +## Как Kafka обрабатывает сообщения? + +Kafka поддерживает два основных способа обработки сообщений: +* **Queue**: каждое сообщение обрабатывается одним потребителем в группе потребителей. Это достигается за счет наличия + в группе нескольких потребителей, каждый из которых считывает данные из отдельных партиций. +* **Publish-Subscribe**: все сообщения обрабатываются всеми потребителями. Это достигается за счет того, что каждый + потребитель находится в своей собственной группе потребителей, что позволяет всем потребителям читать все сообщения. + +[к оглавлению](#apache-kafka) + +## Как Kafka обрабатывает задержку консюмера? + +Задержка (лаг) консюмера в Kafka относится к разнице между оффсетом последнего созданного сообщения и оффсетом последнего +полученного сообщения. Kafka предоставляет инструменты и API для мониторинга задержек консюмеров такие, как инструмент +командной строки Kafka Consumer Groups и API AdminClient. Высокая задержка консюмеров может указывать на проблемы с +производительностью или недостаточную пропускную способность консюмеров. Kafka не обрабатывает задержки автоматически, +но предоставляет информацию, необходимую приложениям для принятия решений о масштабировании или оптимизации производительности. + +[к оглавлению](#apache-kafka) + +## Для чего нужны методы subscribe() и poll()? + +Метод subscribe() используется для подписки на один или несколько топиков. Фактически он не извлекает никаких данных. +Метод poll(), с другой стороны, используется для извлечения данных из топиков. Он возвращает записи, которые были опубликованы +с момента последнего запроса топиков и партиций. Метод poll() обычно вызывается в цикле для непрерывного получения данных. + +[к оглавлению](#apache-kafka) + +## Для чего нужен метод position()? + +Метод position() возвращает смещение следующей записи, которая будет извлечена для данной партиции. Это полезно для +отслеживания хода получения данных и может использоваться в сочетании с методом committed(), чтобы определить насколько +сильно потребитель отстал от своего последнего комита оффсета. Эта информация может быть ценной для мониторинга и +управления показателями потребителей. + +[к оглавлению](#apache-kafka) + +## Для чего нужны методы commitSync() и commitAsync()? + +Эти методы используются для фиксации смещений: +* **commitSync()**: синхронно фиксирует последнее смещение, возвращенное poll(). Он будет повторять попытку до тех пор, + пока не завершится успешно или не столкнется с непроверяемой ошибкой. +* **commitAsync()**: асинхронно фиксирует смещения. Он не повторяет попытку при сбое, что делает его более быстрым, + но менее надежным, чем commitSync(). Выбор между этими методами зависит от баланса между производительностью и надежностью, + требуемого приложением. + +[к оглавлению](#apache-kafka) + +## Другие вопросы + +## Для чего нужен идемпотентный продюсер? + +Идемпотентный продюсер гарантирует exactly-once гарантию доставки, предотвращая дублирование записей в Kafka в случае +повторных попыток отправки сообщений. Это важно для поддержания целостности данных и правильности их обработки в системе, +особенно в распределенных системах, где могут возникать ошибки связи или сбои. + +[к оглавлению](#apache-kafka) + +## Для чего нужен интерфейс Partitioner? + +Интерфейс Partitioner в Producer API определяет в какую партицию топика будет отправлено сообщение. Partitioner по-умолчанию +использует хэш ключа (если он присутствует) для выбора партиции, гарантируя, что сообщения с одним и тем же ключом всегда +отправляются в одну и ту же партицию. Могут быть реализованы пользовательские Partitioner для управления распределением +сообщений по партициям на основе определенной бизнес-логики или характеристик данных. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Broker log cleaner thread? + +Поток очистки журнала в Kafka отвечает за выполнение сжатия журнала. Сжатие журнала - это механизм, при котором Kafka +удаляет избыточные записи, сохраняя только последнее значение для каждого ключа. Это полезно в тех случаях, когда требуется +только последнее обновление для данного ключа, например, для обслуживания changelog или состояния БД. Программа очистки журналов +периодически запускается для сжатия соответствующих партиций. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Kafka Mirror Maker? + +Это инструмент, позволяющий реплицировать данные между кластерами Kafka, потенциально находящихся в разных дата-центрах. +Он работает, потребляя данные из одного кластера и передавая в другой. Можно использовать для создания резервной копии данных, +объединения данных из нескольких дата-центров в единое хранилище или для переноса данных между кластерами. + +[к оглавлению](#apache-kafka) + +## Для чего нужна Schema Registry? + +Kafka Schema Registry предоставляет RESTful интерфейс для хранения и извлечения схем Avro. Schema Registry используется +совместно с Kafka для обеспечения совместимости схем данных между производителями и потребителями. Это особенно полезно +при разработке моделей данных с течением времени, сохраняя обратную и прямую совместимость. + +[к оглавлению](#apache-kafka) + +## Для чего нужен Streams DSL? + +Kafka Streams DSL предоставляет высокоуровневый API для операций потоковой обработки. Он позволяет разработчикам описывать +сложную логику обработки, такую как фильтрация, преобразование, агрегирование и объединение потоков данных. DSL абстрагирует +многие низкоуровневые детали потоковой обработки, упрощая создание и обслуживание приложений потоковой обработки. + +[к оглавлению](#apache-kafka) + +## Как Kafka обеспечивает версионирование сообщений? + +Сама по себе Kafka не обеспечивает версионирование сообщений напрямую, но предоставляет механизмы, позволяющие реализовывать +управление версиями. Одним из распространенных подходов является включение поля версии в схему сообщения. Для более сложных задач +управления версиями используются реестры схем (например, Confluent Schema Registry), которые могут управлять изменением схемы и совместимостью. + +[к оглавлению](#apache-kafka) + +## Как потребители получают сообщения от брокера? + +Kafka использует pull-модель для извлечения сообщений. Потребители запрашивают сообщения у брокеров, а не брокеры +отправляют сообщения потребителям. Это позволяет потребителям контролировать скорость, с которой они получают сообщения. +Потребители отправляют запросы на получение данных от брокера, указывая топик, партицию и начальное смещение для каждой партиции. +Брокер отвечает сообщениями с объемом до указанного максимального предела в байтах. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka Streams и Apache Flink? + +Kafka Streams и Apache Flink — это два мощных инструмента для обработки потоков данных в режиме реального времени, но +они различаются по архитектуре, возможностям и сценариям применения. + +### Сравнение Kafka Streams и Apache Flink + +| **Критерий** | **Kafka Streams** | **Apache Flink** | +|------------------------|---------------------------------------------|-----------------------------------------| +| **Архитектура** | Встроенная библиотека, работающая внутри приложения. Зависит от Kafka. | Независимая распределенная система потоковой обработки данных с возможностью интеграции с различными источниками и приемниками данных. | +| **Обработка данных** | Обрабатывает потоки событий непосредственно из Kafka. Подходит для обработки событий и транзакционных данных с минимальной задержкой. | Поддерживает как потоковую (streaming), так и пакетную (batch) обработку данных. Специализируется на сложной обработке событий с гибкими возможностями управления состоянием. | +| **Зависимость от Kafka**| Построена исключительно вокруг Kafka. Требует Kafka для получения и отправки данных. | Работает с широким спектром источников данных (Kafka, HDFS, базы данных и т. д.). Kafka — лишь один из многих источников. | +| **Установка** | Легко интегрируется в существующее Java/Scala-приложение как библиотека. Не требует развертывания кластеров. | Требует отдельного кластера для выполнения, что подходит для высокопроизводительных распределенных систем. | +| **Управление состоянием** | Встроенное состояние с использованием RocksDB, также поддержка репликации состояния. | Имеет развитую систему управления состоянием, поддерживает сложные функции восстановления состояния и обработки данных. | +| **Гарантия доставки** | Поддерживает "at-least-once" и "exactly-once" семантику, когда Kafka настроена соответствующим образом. | Имеет гибкие гарантии доставки: поддержка "exactly-once", "at-least-once" и "at-most-once". | +| **Масштабируемость** | Масштабируется автоматически вместе с Kafka-партициями. Каждая инстанция потребителя Kafka обрабатывает свою партицию. | Поддерживает масштабирование на уровне задач (task), с более гибкой моделью масштабирования и управления ресурсами. | +| **Обработка событий** | Подходит для обработки событий с низкой задержкой и транзакционными требованиями. | Специализируется на сложной обработке событий, таких как windowing, агрегирование и работа с изменяющимся состоянием. Поддерживает сложные аналитические операции. | +| **Инструменты и API** | Легковесная библиотека с простыми API для работы с потоками данных. Основные операции — фильтрация, маппинг, объединение потоков, windowing. | Продвинутая система с богатыми API для сложных вычислений, поддерживающая потоковую и пакетную обработку, обработку событий и контроль сложных бизнес-процессов. | +| **Требования к ресурсам**| Менее ресурсоемка, так как не требует отдельного кластера. Работает в рамках JVM-приложения. | Требует более высоких вычислительных ресурсов, так как выполняется на отдельном кластере и поддерживает высокую степень параллелизма. | + +### Когда выбрать Kafka Streams +- Если вы уже используете Kafka и вам нужна легковесная библиотека для обработки данных непосредственно внутри вашего приложения. +- Для сценариев с низкой задержкой, где данные приходят из Kafka и должны быть быстро обработаны с минимальными накладными расходами. +- Если вам нужно встроить обработку потоков данных в существующую Java/Scala программу без необходимости развертывания отдельных кластеров. + +### Когда выбрать Apache Flink +- Если вы работаете с потоковой и пакетной обработкой данных, где источники и приемники могут быть не только Kafka, но и другие системы (например, HDFS, базы данных). +- Для сложных задач обработки событий, требующих управления состоянием, временных окон, аналитики и восстановления после сбоев. +- Если ваш проект требует высокой производительности, гибкости, точных гарантий доставки и распределенной обработки в кластере. + +### Заключение +- **Kafka Streams** — это идеальный выбор, если ваша инфраструктура уже основана на Kafka, и вам нужна быстрая и легковесная обработка потоков данных. +- **Apache Flink** — это мощный инструмент для сложных аналитических задач, потоковой обработки данных в режиме реального + времени с поддержкой сложных схем обработки, который предоставляет больше возможностей для работы с разнообразными источниками данных. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka Consumer и Kafka Stream? + +**Kafka Consumer** - это клиент, который читает данные из топика и производит некоторую обработку. Обычно используется для +простых сценариев получения данных. **Kafka Stream**, с другой стороны, более подвинутый клиент, который может потреблять, +обрабатывать и класть данные обратно в Kafka. Он предоставляет DSL для сложных операций потоковой обработки, таких как +фильтрация, преобразование, агрегирование и объединение потоков. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka и Flume? + +**Apache Kafka** и **Apache Flume** — это два популярных инструмента для обработки и передачи данных, однако они имеют +разные цели и архитектуры. Вот основные различия между ними: + +### 1. **Назначение и использование** +- **Kafka**: Это распределенная платформа для потоковой передачи данных, которая обеспечивает высокую пропускную способность +и низкую задержку для обработки больших объемов данных. Kafka используется для создания стриминговых приложений и обработки +данных в реальном времени. Она может быть использована для передачи логов, событий, метрик и других данных, требующих +высокой доступности и масштабируемости. +- **Flume**: Это распределенная система для сбора, агрегации и передачи логов и событий. Flume обычно используется для +доставки логов с серверов в HDFS, HBase или другие системы хранения данных. Его основное предназначение — это сбор данных +из различных источников (например, лог-файлов) и передача их в системы хранения или аналитики. + +### 2. **Архитектура** +- **Kafka**: В Kafka данные отправляются в топики и партиции, которые могут быть независимо прочитаны несколькими потребителями. +Kafka ориентирована на высокую пропускную способность и масштабируемость. Это решает задачу обработки потоковых данных и +событий в реальном времени. +- **Flume**: Flume состоит из **источников (sources)**, **каналов (channels)** и **приемников (sinks)**. Источник получает +данные, канал их буферизует, а приемник отправляет их в конечную систему. Flume использует систему "event-based" и часто +применяется для сбора логов. + +### 3. **Хранение данных** +- **Kafka**: Kafka сохраняет сообщения на диске в течение длительного времени (по умолчанию — до 7 дней) в топиках. +Потребители могут читать данные в любой момент времени, и Kafka поддерживает концепцию **сохранения и ретрансляции данных**. +- **Flume**: Flume не имеет встроенного механизма долговременного хранения. Он просто передает данные в назначенные места +хранения (например, HDFS). Данные в Flume не сохраняются долго, и если система хранения не доступна, они теряются. + +### 4. **Производительность** +- **Kafka**: Kafka предназначен для работы с высокими объемами данных. Он поддерживает масштабируемость как по производителям, +так и по потребителям, и может обрабатывать миллионы сообщений в секунду с минимальной задержкой. +- **Flume**: Flume может быть менее масштабируемым по сравнению с Kafka и больше ориентирован на сбор логов и событий +с различных источников. Хотя Flume тоже может обрабатывать большие объемы данных, он не предназначен для работы с +такими большими потоками, как Kafka. + +### 5. **Использование и кейсы** +- **Kafka**: Используется для стриминга данных, аналитики в реальном времени, интеграции различных систем, работы с +большими данными и построения событийных приложений. +- **Flume**: Используется для сбора, агрегации и передачи логов и событий в системы хранения, такие как HDFS, HBase, +или внешние системы. Это идеальный выбор для организации потоков логирования и мониторинга. + +### 6. **Поддержка и интеграция** +- **Kafka**: Kafka поддерживает широкий спектр интеграций и может быть использован с различными системами для построения +распределенных приложений и аналитических решений. +- **Flume**: Flume ориентирован на интеграцию с Hadoop-экосистемой, и основное его использование — это интеграция с HDFS, +HBase и другими хранилищами данных в этой экосистеме. + +### 7. **Потребительская модель** +- **Kafka**: Kafka поддерживает много потребителей, которые могут читать из одного и того же топика независимо, а также +возможность **повторного прочтения данных**. +- **Flume**: Flume имеет фиксированную схему доставки данных и не поддерживает такую гибкость, как Kafka в части потребителей и обработки. + +### 8. **Гарантии доставки** +- **Kafka**: Kafka поддерживает **гарантии доставки** с различными уровнями подтверждения (acknowledgment), а также может +обеспечивать **доставку сообщений точно один раз** (exactly-once semantics). +- **Flume**: Flume обеспечивает базовые гарантии доставки, но они менее строгие, чем у Kafka, и больше ориентированы на +устойчивость к сбоям, а не на гарантированную доставку. + +[к оглавлению](#apache-kafka) + +## В чем разница между Kafka и RabbitMQ? + +**RabbitMQ** и **Apache Kafka** — это две популярные системы обмена сообщениями, каждая из которых имеет свои особенности +и используется для разных типов приложений. Вот основные различия между ними: + +### 1. **Архитектура** +- **RabbitMQ** использует **очереди сообщений**. Сообщения отправляются в очередь, и один потребитель извлекает сообщение +из очереди для обработки. +- **Apache Kafka** использует **топики и партиции**. Сообщения отправляются в топики, которые могут быть разделены на +партиции, и несколько потребителей могут читать эти сообщения в любом порядке. Kafka ориентирован на большие потоки данных и масштабируемость. + +### 2. **Модель доставки сообщений** +- **RabbitMQ**: Сообщения передаются в очереди, и каждый потребитель получает одно сообщение. Сообщения могут быть +подтверждены (acknowledged) или отклонены (rejected). RabbitMQ гарантирует, что сообщение будет доставлено хотя бы одному потребителю. +- **Kafka**: Сообщения сохраняются в топиках на длительный срок, и потребители могут читать их в любом порядке. Kafka +гарантирует доставку сообщений всем потребителям, если они подписаны на топик, и может позволить многократное чтение старых сообщений. + +### 3. **Гарантии доставки** +- **RabbitMQ**: Предоставляет подтверждения доставки и может повторно отправить сообщение, если потребитель не подтвердил +его получение. Можно настроить разные уровни надежности (например, за счет использования подтверждений или транзакций). +- **Kafka**: Сообщения сохраняются на диске, что позволяет потребителям считывать их в любое время. Kafka гарантирует +доставку сообщений при определенной конфигурации репликации и сохранения. + +### 4. **Производительность и масштабируемость** +- **RabbitMQ**: Лучше подходит для небольших и средних систем, где требуется высокая надежность и гарантированная доставка. +Он поддерживает **горизонтальное масштабирование**, но требует дополнительных усилий для настройки и управления. +- **Kafka**: Отличается высокой **производительностью** и возможностью обработки больших объемов данных. Kafka легко +масштабируется за счет **партиционирования** и репликации данных. + +### 5. **Потребительская модель** +- **RabbitMQ**: Один потребитель получает одно сообщение. Если потребитель не успевает обработать сообщение, оно может быть повторно отправлено. +- **Kafka**: Потребители могут читать сообщения независимо друг от друга. Kafka сохраняет все сообщения в топиках, +и потребители могут читать их в любое время. Kafka также поддерживает концепцию **групп потребителей**, где каждый +потребитель группы обрабатывает разные партиции. + +### 6. **Использование и кейсы** +- **RabbitMQ**: Идеален для обработки запросов и ответов, распределенных приложений, микросервисов с гарантией доставки, +бизнес-процессов с очередями задач. +- **Kafka**: Используется для обработки потоков данных, интеграции с большими данными, записи журналов, мониторинга, +обработки событий в реальном времени и сохранения больших объемов данных для последующего анализа. + +### 7. **Производители и потребители** +- **RabbitMQ**: Один производитель отправляет сообщения в очередь, и несколько потребителей могут обрабатывать эти сообщения. +- **Kafka**: Множество производителей могут отправлять сообщения в топики, и несколько потребителей могут читать их +одновременно, поддерживая масштабируемость. + +### 8. **Сообщения и хранение** +- **RabbitMQ**: Сообщения удаляются из очереди после их обработки потребителем. Хранение сообщений обычно краткосрочное. +- **Kafka**: Сообщения сохраняются на диске в топиках до тех пор, пока не истечет срок хранения (по конфигурации). +Это позволяет повторно читать данные. + +[к оглавлению](#apache-kafka) diff --git a/reactive.md b/reactive.md new file mode 100644 index 0000000..17f0ef8 --- /dev/null +++ b/reactive.md @@ -0,0 +1,584 @@ +[Вопросы для собеседования](README.md) + +# Реактивное программирование +* [Что такое реактивное программирование и чем оно отличается от процедурного программирования?](#что-такое-реактивное-программирование-и-чем-оно-отличается-от-процедурного-программирования) +* [Объясните концепцию потоков данных в реактивном программировании](#объясните-концепцию-потоков-данных-в-реактивном-программировании) +* [Что такое паттерн Observer и как он лежит в основе реактивного программирования?](#что-такое-паттерн-observer-и-как-он-лежит-в-основе-реактивного-программирования) +* [Опишите роль Observable и Observer в реактивном программировании](#опишите-роль-observable-и-observer-в-реактивном-программировании) +* [Что такое backpressure в контексте реактивного программирования?](#что-такое-backpressure-в-контексте-реактивного-программирования) +* [Объясните разницу между Hot и Cold Observable](#объясните-разницу-между-hot-и-cold-observable) +* [Какова роль Подписки в реактивном программировании?](#какова-роль-подписки-в-реактивном-программировании) +* [Как отписаться от потока для предотвращения утечки памяти?](#как-отписаться-от-потока-для-предотвращения-утечки-памяти) +* [Какие есть операторы в Project Reactor и для чего они используются?](#какие-есть-операторы-в-project-reactor-и-для-чего-они-используются) + +## Что такое реактивное программирование и чем оно отличается от процедурного программирования? + +### Основные принципы + +**Процедурное программирование** - это подход, при котором программа состоит из последовательности инструкций, выполняемых одна за другой. +В процедурном программировании акцент делается на определении функций и процедур, которые выполняют определенные задачи. +Этот подход хорошо подходит для решения задач, требующих четкого алгоритма действий. + +**Реактивное программирование**, с другой стороны, фокусируется на обработке потоков данных и событий. +В реактивном программировании программа реагирует на изменения в данных или событиях, происходящих в реальном времени. +Реактивное программирование позволяет создавать более гибкие и эффективные системы, способные адаптироваться к изменениям +в данных и событиях без необходимости явного управления асинхронными задачами. + +Процедурное программирование представляет данные в виде единственного значения, хранящегося в переменной. +Реактивное программирование представляет собой непрерывный поток данных, на который могут подписаться несколько наблюдателей. + +[к оглавлению](#реактивное-программирование) + +## Объясните концепцию потоков данных в реактивном программировании + +Концепция потоков данных в реактивном программировании заключается в представлении данных как непрерывно изменяющегося потока, +который автоматически распространяется через систему. Это отличается от традиционного императивного программирования, где данные +обычно обрабатываются как отдельные элементы и изменения должны явно инициироваться кодом. + +В реактивном программировании данные представлены как поток событий, каждое из которых может содержать новое значение или изменение состояния. +Система автоматически реагирует на эти изменения, обновляя свое состояние соответствующим образом. Это позволяет создавать +приложения, которые эффективно обрабатывают большие объемы данных и быстро реагируют на изменения, происходящие в реальном времени. + +Примером может служить система управления данными, которая автоматически обновляет пользовательский интерфейс при изменении данных в базе. +В таком случае, пользовательский интерфейс будет автоматически обновляться каждый раз, когда происходит изменение данных, +без необходимости явного запроса на обновление со стороны пользователя. + +Реактивное программирование основано на шаблоне Наблюдатель (Observer) + +### Ключевые компоненты +* **Наблюдаемый (Observable)** представляет источник данных. При изменении его состояния (или при создании новых данных) изменения передаются наблюдателям +* **Наблюдатель (Observer)** подписывается на Observable и получает уведомления о любых изменениях состояния или новых данных +* **Подписка (Subscription)** устанавливает взаимосвязь между наблюдаемым и наблюдателем. Подписка может быть "один к одному" или "один ко многим" +* **Операторы (Operators)** часто называемые функциями преобразования, они позволяют изменять или адаптировать данные из наблюдаемого объекта до того, как они попадут к наблюдателю +* **Планировщики (Schedulers)** помогают управлять временем и порядком выполнения операций в таких сценариях, как фоновая работа и обновления пользовательского интерфейса +* **Subjects** совмещают роли объекта наблюдения и наблюдателя. Это могут быть как источники данных, так и потребители данных + +### Процесс передачи данных +* **Эмиссия (Emission)** - данные создаются в наблюдаемом объекте и отправляются его наблюдателям +* **Фильтрация (Filtering)** - операторы могут просматривать входящие данные, пересылая только те, которые соответствуют определенным критериям +* **Трансформация (Transformation)** - данные изменяются — например, путем их мапинга перед передачей наблюдателю +* **Нотификация (Notification)** - информирование наблюдателей при поступлении новых данных + +### Основные характеристики потоков +* **Непрерывность (Continuous)** - поток данных сохраняется, что позволяет осуществлять взаимодействие в режиме реального времени +* **Асинхронность (Asynchronous)** - не гарантируется, что события будут происходить в определенном порядке, что позволяет выполнять неблокирующие операции +* **Однонаправленность (One-directional)** - данные передаются от Observable к его подписчикам, обеспечивая однонаправленный поток + +### Типы потоков по количеству подписчиков +* **Unicast Streams** - у каждого наблюдателя есть эксклюзивное подключение к наблюдаемому источнику +* **Broadcast Streams** - позволяет нескольким наблюдателям подписаться на один объект наблюдения. Каждый наблюдатель +получает полный набор данных, что может быть проблематично, если речь идет о конфиденциальности данных + +### Типы потоков по поведению +* **Hot Observable** - эти последовательности передают данные независимо от присутствия наблюдателя. +Если подписывается новый наблюдатель, он начинает получать данные с точки подписки +* **Cold Observable** - здесь передача данных начинается только после подписки. Любой новый наблюдатель получит данные с самого начала + +### Backpressure +Данный механизм регулируют скорость, с которой данные публикуются в поток. Это необходимо, чтобы справиться с потенциальным +переполнением или узкими местами из-за различий в скоростях обработки данных. + +Например, в RxJava интерфейсы `Observable` и `Flowable` отличаются тем, что последний включает поддержку backpressure. +С `Flowable` можно использовать настраиваемую стратегию backpressure, чтобы контролировать скорость публикации Observable относительно скорости потребления Subscriber + +### Практическое применение +Будь то обработка асинхронных вызовов API или управление вводом данных пользователем, потоки данных обеспечивают надежную +и гибкую основу для многих повседневных задач программирования. + +Можно использовать ряд операторов, таких как `map`, `filter`, `debounce`, и `throttle`, для преобразования данных +и манипулирования ими, исходя из конкретных требований. + +Широкое внедрение реактивных библиотек, таких как RxJava для Android или RxJS для Web, подчеркивает +полезность потоков данных в современной разработке программного обеспечения. + +[к оглавлению](#реактивное-программирование) + +## Что такое паттерн Observer и как он лежит в основе реактивного программирования? + +Паттерн Observer, также известный как Publish/Subscribe или Event Listener, является поведенческим шаблоном проектирования, +который позволяет объектам следить за изменениями в других объектах и реагировать на них. Это один из самых популярных и +полезных шаблонов, который упрощает код и повышает его гибкость. В основе реактивного программирования лежит идея о том, +что система должна реагировать на изменения внешних источников данных или событий. Паттерн Observer идеально подходит для +реализации этой концепции, поскольку он позволяет объектам автоматически получать уведомления об изменениях в других объектах +и соответствующим образом обновлять свое состояние. + +Пример использования паттерна Observer в веб-разработке может включать систему уведомлений для пользователей. Когда новая +статья добавляется на сайт, все подписчики должны быть уведомлены об этом. В этом случае, класс Subject будет отвечать +за управление подписчиками и их уведомление об изменениях, а класс Observer будет представлять собой простого наблюдателя, +который выводит сообщение о новой статье при получении уведомления, таким образом обеспечивается **слабую связность (loose coupling)**. + +Применение паттерна Observer в веб-разработке может быть полезно для обработки событий пользовательского интерфейса, +реализации системы уведомлений для пользователей, отслеживания изменений состояния приложения и реагирования на них. +Однако важно помнить, что чрезмерное использование паттерна может привести к усложнению кода и затруднить отладку. + +### Ключевые компоненты +* **Subject** - источник данных или событий. Наблюдатели подписываются на Subject для получения уведомлений об изменениях +* **Observer** - наблюдатель получает уведомления, когда состояние Subject изменяется + +В реактивной конфигурации Subject отвечает за публикацию изменений, а Observers подписываются на эти изменения. +Это исключает явное обращение к источникам данных и подчеркивает **модель потока данных (datastream model)**. + +### Пример кода паттерна Observer + +```java +import java.util.ArrayList; +import java.util.List; + +interface Observer { + void update(); +} + +class Subject { + private List observers = new ArrayList<>(); + private int state; + + public int getState() { + return state; + } + + public void setState(int state) { + this.state = state; + notifyAllObservers(); + } + + public void attach(Observer observer) { + observers.add(observer); + } + + public void notifyAllObservers() { + for (Observer observer : observers) { + observer.update(); + } + } +} + +class ConcreteObserver implements Observer { + private String name; + private Subject subject; + + public ConcreteObserver(String name, Subject subject) { + this.name = name; + this.subject = subject; + } + + @Override + public void update() { + System.out.println("Observer " * name * " updated. New state: " * subject.getState()); + } +} + +public class Main { + public static void main(String[] args) { + Subject subject = new Subject(); + ConcreteObserver observer1 = new ConcreteObserver("One", subject); + ConcreteObserver observer2 = new ConcreteObserver("Two", subject); + + subject.attach(observer1); + subject.attach(observer2); + + subject.setState(5); + } +} +``` +В данном примере Subject ведет список подписавшихся Observers и уведомляет их при изменении его состояния. + +[к оглавлению](#реактивное-программирование) + +## Опишите роль Observable и Observer в реактивном программировании + +**Наблюдатели** являются потребителями данных, в то время как **наблюдаемые** являются источником или производителем данных. + +### Ключевые концепции +* **Наблюдаемый (Observable)** - передает данные или сигналы, которые могут быть любых типов, включая пользовательские события +* **Наблюдатель (Observer)** - получает уведомление, когда Observable отправляет данные +* **Подписка (Subscription)** - связующее звено между объектом наблюдения и наблюдателем +* **Операторы (Operators)** - позволяют преобразовывать, фильтровать, комбинировать или обрабатывать поток данных, +публикуемый наблюдаемым объектом, до того, как он достигнет наблюдателя + +### Пример кода: Observable и Observer + +### Java 9* + +**Определить Subscriber** + +```java +import java.util.concurrent.Flow; + +public class SimpleSubscriber implements Flow.Subscriber { + private Flow.Subscription subscription; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1); // Запрашиваем первый элемент + } + + @Override + public void onNext(String item) { + System.out.println("Received: " * item); + subscription.request(1); // Запрашиваем следующий элемент + } + + @Override + public void onError(Throwable throwable) { + System.err.println("Error: " * throwable.getMessage()); + } + + @Override + public void onComplete() { + System.out.println("All items received"); + } +} +``` + +**Определить Publisher** + +```java +import java.util.concurrent.Flow; +import java.util.concurrent.SubmissionPublisher; +import java.util.concurrent.TimeUnit; + +public class SimplePublisher { + + public static void main(String[] args) throws InterruptedException { + // Создаем издателя + SubmissionPublisher publisher = new SubmissionPublisher<>(); + + // Создаем подписчика + SimpleSubscriber subscriber = new SimpleSubscriber(); + + // Регистрируем подписчика в издателе + publisher.subscribe(subscriber); + + // Публикуем элементы + System.out.println("Publishing data items..."); + String[] items = {"item1", "item2", "item3"}; + for (String item : items) { + publisher.submit(item); + TimeUnit.SECONDS.sleep(1); + } + + // Закрываем издателя + publisher.close(); + + // Ждем некоторое время, чтобы подписчик обработал все элементы + TimeUnit.SECONDS.sleep(3); + } +} +``` + +### Project Reactor + +```java +import reactor.core.publisher.Flux; + +public class ReactorExample { + + public static void main(String[] args) { + // Создаем Flux для публикации данных + Flux flux = Flux.just("Hello", "World", "From", "Reactor"); + + // Подписываемся на Flux и выводим каждый элемент + flux.subscribe( + item -> System.out.println("Received: " * item), + error -> System.err.println("Error: " * error), + () -> System.out.println("All items received") + ); + } +} +``` + +[к оглавлению](#реактивное-программирование) + +## Что такое backpressure в контексте реактивного программирования? + +**Backpressure** - это концепция в реактивном программировании, которая имеет дело с ситуацией, когда производитель (или издатель) +генерирует данные быстрее, чем потребитель (или подписчик) может их обработать. Управление backpressure позволяет системе +оставаться отзывчивой и не перегружаться. + +### Ключевые концепции backpressure + +* **Producer (Publisher)** - компонент, который производит данные +* **Consumer (Subscriber)** - компонент, который потребляет данные +* **Flow Control** - механизм, который гарантирует, что производитель не перегрузит потребителя слишком большим объемом данных + +### Почему важно backpressure? + +В реактивной системе, если потребитель не выдерживает скорость, с которой производитель производит данные, это может привести к следующим проблемам: +* **Переполнение памяти (Memory Overflow)** - необработанные элементы могут накапливаться в памяти, что приводит к ошибкам нехватки памяти +* **Увеличение задержки (Latency Increase)** - система может перестать отвечать по мере роста очереди необработанных элементов +* **Исчерпание ресурсов (Resource Exhaustion)** - системные ресурсы (процессор, память) могут быть исчерпаны, что приводит к снижению производительности или сбоям + +### Стратегии управления backpressure в Project Reactor + +* **Буферизация (Buffering)** - входящие элементы хранятся в буфере до тех пор, пока потребитель не сможет их обработать + * **onBackpressureBuffer(100)** + +```java +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +public class BackpressureExample { + + public static void main(String[] args) { + Flux flux = Flux.range(1, 1000) + .onBackpressureBuffer(100); // Устанавливаем стратегию backpressure + + flux.publishOn(Schedulers.boundedElastic()) + .subscribe( + item -> { + try { + Thread.sleep(10); // Имитируем медленного потребителя + System.out.println("Received: " * item); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }, + error -> System.err.println("Error: " * error), + () -> System.out.println("All items received") + ); + } +} +``` + +* **Отбрасывание (Dropping)** - отбрасывает элементы, если потребитель не может их обработать + * **onBackpressureDrop()** +* **Новейшие элементы (Latest)** - сохраняет только последние элементы, удаляя предыдущие + * **onBackpressureLatest()** +* **Ошибка (Error)** - сигнализирует об ошибке, когда backpressure не может быть обработано + * **onBackpressureError()** +* **Контроль скорости запроса (Control Request Rate)**: явно контролирует скорость, с которой потребитель запрашивает элементы у производителя + * **request(n)** - метод в реализации Subscriber для управления потоком + +```java +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; + +public class ControlledRequestExample { + + public static void main(String[] args) { + Flux flux = Flux.range(1, 1000); + + flux.subscribe(new BaseSubscriber() { + @Override + private void hookOnSubscribe(Subscription subscription) { + request(1); // Запрашиваем один элемент при подписке + } + + @Override + private void hookOnNext(Integer value) { + try { + Thread.sleep(10); // Эмитируем медленный процесс + System.out.println("Received: " * value); + request(1); // Запрашиваем следующий элемент после обработки текущего + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + private void hookOnComplete() { + System.out.println("All items received"); + } + + @Override + private void hookOnError(Throwable throwable) { + System.err.println("Error: " * throwable.getMessage()); + } + }); + } +} +``` + +[к оглавлению](#реактивное-программирование) + +## Объясните разницу между Hot и Cold Observable + +В реактивном программировании термины hot и cold observable (или издатели в контексте Project Reactor) описывают, как они +создают потоки данных и обрабатывают их. Основное различие между ними заключается в том, как они обрабатывают подписки +и когда начинают выдавать элементы. + +### Cold Observables + +Начинают выдавать элементы только тогда, когда подписчик подписывается на них. Каждый подписчик получает всю последовательность +элементов с самого начала. Это означает, что каждый раз, когда подписывается новый подписчик, Observable воспроизводит всю последовательность элементов. + +#### Характеристики + +* **Ленивое исполнение (Lazy Evaluation)** - данные не производятся, пока не будет хотя бы одного подписчика +* **Множественные подписки (Multiple Subscriptions)** - каждый подписчик получает полную последовательность элементов независимо от других подписчиков +* **Воспроизводимость (Reproducibility)** - каждый подписчик видит одну и ту же последовательность элементов с самого начала, что делает поток воспроизводимым + +#### Пример + +```java +import reactor.core.publisher.Flux; + +public class ColdObservableExample { + + public static void main(String[] args) { + Flux coldFlux = Flux.just("A", "B", "C", "D") + .doOnSubscribe(subscription -> System.out.println("Subscribed to Cold Observable")); + + // First subscription + coldFlux.subscribe(item -> System.out.println("Subscriber 1: " * item)); + + // Second subscription + coldFlux.subscribe(item -> System.out.println("Subscriber 2: " * item)); + } +} +``` + +### Hot Observables + +Начинают выдавать элементы независимо от наличия подписчиков. Подписчики получают только те элементы, которые были отправлены +после их подписки. Это означает, что если подписчик подпишется с опозданием, он пропустит элементы, которые были отправлены до подписки. + +#### Характеристики + +* **Жадное исполнение (Eager Evaluation)** - публикация элементов происходит сразу после создания, даже если подписчиков нет +* **Общий поток данных (Shared Data Stream)** - все подписчики используют один и тот же источник данных и получают элементы, отправленные после подписки +* **Невоспроизводимость (Non-Reproducibility)** - подписчики могут видеть разные части последовательности в зависимости от того, когда они подписались + +#### Пример + +```java +import reactor.core.publisher.Flux; +import reactor.core.publisher.ConnectableFlux; + +import java.time.Duration; + +public class HotObservableExample { + + public static void main(String[] args) throws InterruptedException { + ConnectableFlux hotFlux = Flux.just("A", "B", "C", "D") + .delayElements(Duration.ofMillis(500)) + .publish(); + + // Запускаем публикацию элементов + hotFlux.connect(); + + // Первая подписка (начинает получать данные немедленно) + hotFlux.subscribe(item -> System.out.println("Subscriber 1: " * item)); + Thread.sleep(750); // Ждем отправку элементов + + // Вторая подписка (пропускает первый элемент) + hotFlux.subscribe(item -> System.out.println("Subscriber 2: " * item)); + + // Останавливаем работу основного потока, чтобы увидеть выходные данные + Thread.sleep(2000); + } +} + +``` + +### Ключевые отличия + +| Критерий | Hot Observables | Cold Observables | +|----------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------| +| Обмен данными | Один поток для всех подписчиков | У каждого подписчика свой независимый поток | +| Время подписки | Получает данные в зависимости от времени подписки | Получает все данные, даже если подпишется позже | +| Жизненный цикл | Работает независимо от подписок | Запускает генерацию данных только, когда есть подписка | +| Асинхронность | Может генерировать и передавать данные без подписчиков | Передача данных начинается после подписки, что часто приводит к синхронной передаче | + +### Практическое применение + +Cold Observables полезны для: +* Данные, которые необходимо воспроизвести для каждого подписчика, такие как чтение из файла, выполнение HTTP-запроса или +генерация новой случайной последовательности. +* Сценарии, в которых последовательность элементов должна быть согласованной и воспроизводимой для каждого подписчика. + +Hot Observables полезны для: +* Данные, которые создаются непрерывно и которыми необходимо делиться между несколькими подписчиками, такие как события +мыши, обновления цен на акции или данные датчиков. +* Сценарии, в которых подписчики должны получать только текущие и будущие события, а не прошлые. + +[к оглавлению](#реактивное-программирование) + +## Какова роль Подписки в реактивном программировании? + +Подписка абстрагирует от того, как данные получаются или генерируются + +### Основные функции +`Subscription` обычно предлагает два основных метода: +* **Request** - информирует источник данных о количестве элементов, которые потребитель готов получить +* **Cancel** - останавливает поток данных, освобождая любые ресурсы, такие как обработчики файлов или сетевые подключения + +### Общая концепция +`Subscription` - интерфейс, действующий как соглашение между источником данных и потребителем данных. Он обеспечивает +передачу данных с учетом управления потоком, backpressure и ресурсами. + +### Управление backpressure +Реализации интерфейса `Publisher` в реактивных потоках оценивают готовность подписчика обрабатывать входящие данные +с учетом текущего состояния потока данных. Этот механизм, известный как backpressure, направлен на предотвращение перегрузки +путем указания источнику данных соответствующим образом адаптировать скорость передачи данных. + +`request` - метод интерфейса `Subscription` является основным каналом, по которому подписчик сообщает источнику данных +о своей текущей возможности принимать данные, тем самым регулируя backpressure. + +### Управление ресурсами +Для определенных источников данных, таких как файлы, потоки ввода-вывода или базы данных, могут потребоваться определенные +ресурсы. Интерфейс `Subscription` предоставляет средства для освобождения этих ресурсов, когда передача данных больше не требуется. + +После вызова метода `cancel` источник данных может предпринять соответствующие действия, такие как закрытие файла или +прекращение сетевого взаимодействия. + +[к оглавлению](#реактивное-программирование) + +## Как отписаться от потока для предотвращения утечки памяти? + +* Использовать `Disposable`: получить Disposable из подписки и вызвать метод `dispose`, чтобы отменить ее +* Использовать `BaseSubscriber`: наследоваться от класса BaseSubscriber и вызвать потом метод `dispose` +* Использовать операторы при создании потока: + * `take`: автоматически отменит подписку после получения некоторого количества элементов + * `timeout`: автоматически отменяет подписку, если в течение указанного срока не будет отправлено никаких элементов. + +Best Practice: стоит настраивать отмену подписки, связывая ее с жизненным циклом какого-либо компонента + +[к оглавлению](#реактивное-программирование) + +## Какие есть операторы в Project Reactor и для чего они используются? + +Операторы в реактивном программировании служат для создания, преобразования, фильтрации или объединения различных потоков данных. + +### Операторы создания +* `just`: создает Flux/Mono, который публикует указанные элементы +* `fromArray`: создает поток, который генерирует элементы из массива +* `fromIterable`: создает Flux, который генерирует элементы из итерируемого объекта +* `fromStream`: создает Flux из stream Java +* `fromCallable`: создает Mono из Callable +* `fromRunnable`: создает Mono из Runnable +* `fromSupplier`: создает Mono от Supplier +* `range`: создает FLux, который выдает диапазон целых чисел +* `interval`: создает Flux, который выдает long значения через регулярные промежутки времени +* `empty`: создает пустой Flux/Mono, который завершается немедленно +* `error`: создает Flux/Mono, который немедленно сигнализирует об ошибке +* `never`: создает Flux/Mono, который не создает какой-либо элемент и не завершается +* `defer`: создает новый Flux/Mono для каждой подписки + +### Операторы трансформации +* `map`: преобразует объекты, публикуемые Flux/Mono. +* `flatMap`: преобразует каждый элемент в поток, а затем соединяет их в один поток +* `concatMap`: как flatMap, но поддерживает порядок публикуемых элементов +* `switchMap`: когда он получает данные от нового потока, то сразу отписывается от предыдущего и подписывается на новый +* `scan`: Накапливайте состояние каждого элемента. +* `buffer`: собирает элементы в как список внутри Flux +* `window`: публикует коллекцию элементов как Flux (окно фиксированного размера) внутри Flux +* `groupBy`: группирует элементы по ключу + +### Операторы фильтрации +* `filter`: пропускает только те элементы, которые удовлетворяют условию +* `distinct`: пропускает только уникальные элементы +* `take`: ограничивает количество элементов, публикуемых потоком +* `takeWhile`: публикует элементы, пока условие истинно +* `takeUntil`: публикует элементы, пока условие не станет истинно +* `skip`: пропускает определенное количество элементов в начале потока +* `skipWhile`: пропускает элементы, пока условие истинно +* `skipUntil`: пропускает элементы, пока условие не станет истинно + +### Операторы объединения +* `merge`: объединяет потоки в один параллельно, сохраняя порядок элементов (активная подписка) +* `concat`: объединяет потоки последовательно, ожидая завершения первого потока, затем второго и так далее (отложенная подписка) +* `zip`: объединяет элементы из нескольких потоков в пары +* `combineLatest`: объединяет указанным способом последние значения из нескольких потоков +* `startWith`: добавляет в начало потока к исходным элементам новые элемент(ы) From f335ccd4c9db631ce7bd1df01e6c33737059a794 Mon Sep 17 00:00:00 2001 From: Enchased Horse Date: Wed, 20 Nov 2024 08:07:48 +0300 Subject: [PATCH 50/58] Update README.md Reorder content items --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index dc9ccc8..dff913e 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ + [Основы HTML](#Основы-html) ![icon][done] + [Основы CSS](#Основы-css) ![icon][done] + [Основы Web](#Основы-web) ![icon][done] -+ [Дополнительные материалы](#Дополнительные-материалы) ![icon][done] + [Apache Kafka](#apache-kafka) ![icon][done] ++ [Дополнительные материалы](#Дополнительные-материалы) ![icon][done] [done]:done.png @@ -761,19 +761,6 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) -## Дополнительные материалы -+ [4 толковых канала на Youtube про технические собеседования](https://habr.com/ru/post/454264/) -+ [A list of fancy questions I've been asked during the interviews I had](https://github.com/d1mnewz/interviews) -+ [Job interview in English: как готовиться и что отвечать](https://dou.ua/lenta/articles/interview-in-english/) -+ [Senior Engineer в поисках работы. О задачах на технических собеседованиях и теоретических вопросах](https://habr.com/ru/post/442442/) -+ [What to ask an interviewer during a tech interview](https://hackernoon.com/what-to-ask-an-interviewer-during-a-tech-interview-865a293e548c) -+ [Spring Boot Interview Questions](https://www.baeldung.com/spring-boot-interview-questions) -+ [Top Spring Framework Interview Questions](https://www.baeldung.com/spring-interview-questions) -+ [Spring Interview Questions](https://www.interviewbit.com/spring-interview-questions/) -+ [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) - -[к оглавлению](#Вопросы-для-собеседования-на-java-developer) - ## Apache Kafka * [Что такое Apache Kafka?](kafka.md#что-такое-apache-kafka) @@ -837,5 +824,18 @@ [к оглавлению](#Вопросы-для-собеседования-на-java-developer) +## Дополнительные материалы ++ [4 толковых канала на Youtube про технические собеседования](https://habr.com/ru/post/454264/) ++ [A list of fancy questions I've been asked during the interviews I had](https://github.com/d1mnewz/interviews) ++ [Job interview in English: как готовиться и что отвечать](https://dou.ua/lenta/articles/interview-in-english/) ++ [Senior Engineer в поисках работы. О задачах на технических собеседованиях и теоретических вопросах](https://habr.com/ru/post/442442/) ++ [What to ask an interviewer during a tech interview](https://hackernoon.com/what-to-ask-an-interviewer-during-a-tech-interview-865a293e548c) ++ [Spring Boot Interview Questions](https://www.baeldung.com/spring-boot-interview-questions) ++ [Top Spring Framework Interview Questions](https://www.baeldung.com/spring-interview-questions) ++ [Spring Interview Questions](https://www.interviewbit.com/spring-interview-questions/) ++ [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) + +[к оглавлению](#Вопросы-для-собеседования-на-java-developer) + ## Источники + [Вопросы на собеседование Junior Java Developer](https://jsehelper.blogspot.ru) From d139504dde28c821b3e2e9a34e074d130c073231 Mon Sep 17 00:00:00 2001 From: OleksandrDraha <79225501+OleksandrDraha@users.noreply.github.com> Date: Wed, 20 Nov 2024 07:09:06 +0200 Subject: [PATCH 51/58] Update oop.md (#123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like there is an inconsistency between examples of paragraphs ("инкапсуляция" and "наследование") as AbstractPhone class was not defined but was inherited by WirelessPhone class (and another following classes) with overriding of methods call() and ring() --- oop.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oop.md b/oop.md index baa3e7b..8464512 100644 --- a/oop.md +++ b/oop.md @@ -50,11 +50,11 @@ __Инкапсуляция__ – это свойство системы, поз Пример: ```java -public class SomePhone { +public class AbstractPhone { private int year; private String company; - public SomePhone(int year, String company) { + public AbstractPhone (int year, String company) { this.year = year; this.company = company; } From d0d25064c187f0cf62c47b77921559a6ea699eab Mon Sep 17 00:00:00 2001 From: JackieL Date: Mon, 13 Jan 2025 17:33:40 +0800 Subject: [PATCH 52/58] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B9=20=D1=80=D0=B5?= =?UTF-8?q?=D1=81=D1=83=D1=80=D1=81=20=D0=B2=20=D0=9F=D0=BE=D0=BF=D1=83?= =?UTF-8?q?=D0=BB=D1=8F=D1=80=D0=BD=D1=8B=D0=B5=20(#164)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dff913e..17ff0b3 100644 --- a/README.md +++ b/README.md @@ -834,6 +834,8 @@ + [Top Spring Framework Interview Questions](https://www.baeldung.com/spring-interview-questions) + [Spring Interview Questions](https://www.interviewbit.com/spring-interview-questions/) + [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) ++ [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) ++ [Java Interview Questions](https://labex.io/interview-questions/java) [к оглавлению](#Вопросы-для-собеседования-на-java-developer) From 5a8b16977fe1755fec66da9bfbcbbe428ae8dc8f Mon Sep 17 00:00:00 2001 From: VladislavI1I1I <67649664+VladislavI1I1I@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:52:49 +0300 Subject: [PATCH 53/58] Update core.md (#165) --- core.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core.md b/core.md index f20e28b..f7b6100 100644 --- a/core.md +++ b/core.md @@ -1273,8 +1273,7 @@ public native int hashCode(); ## Если у класса `Point{int x, y;}` реализовать метод `equals(Object that) {(return this.x == that.x && this.y == that.y)}`, но сделать хэш код в виде `int hashCode() {return x;}`, то будут ли корректно такие точки помещаться и извлекаться из `HashSet`? `HashSet` использует `HashMap` для хранения элементов. При добавлении элемента в `HashMap` вычисляется хэш код, по которому определяется позиция в массиве, куда будет вставлен новый элемент. У всех экземпляров класса `Point` хэш код будет одинаковым для всех объектов с одинаковым `x`, что приведёт к вырождению хэш таблицы в список. -При возникновении коллизии в `HashMap` осуществляется проверка на наличие элемента в списке: `e.hash == hash && ((k = e.key) == key || key.equals(k))`. Если элемент найден, то его значение перезаписывается. В нашем случае для разных объектов метод `equals()` будет возвращать `false`. Соответственно новый элемент будет успешно добавлен в `HashSet`. Извлечение элемента также будет осуществляться успешно. Но производительность такого кода будет невысокой и преимущества хэш таблиц использоваться не будут. - +При возникновении коллизии в `HashMap` осуществляется проверка на наличие элемента в списке: `e.hash == hash && ((k = e.key) == key || key.equals(k))`. Если элемент найден, то его значение перезаписывается. В нашем случае для разных объектов метод `equals()` будет возвращать `false`. Соответственно новый элемент будет успешно добавлен в `HashSet`. Извлечение элемента также будет осуществляться успешно. Но производительность такого кода будет невысокой, из-за неэффективности хэш-функции, которая cпособна породить большое количество колизий. [к оглавлению](#java-core) ## Могут ли у разных объектов `(ref0 != ref1)` быть `ref0.equals(ref1) == true`? From 258a0a1695e5b4d0c1a68a8688634387b7667d97 Mon Sep 17 00:00:00 2001 From: Sergey Melnikov <70698479+melniknow@users.noreply.github.com> Date: Fri, 25 Apr 2025 20:11:32 +0600 Subject: [PATCH 54/58] Fix typos (#170) Co-authored-by: Sergey Melnikov --- db.md | 2 +- java8.md | 2 +- jcf.md | 2 +- jdbc.md | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/db.md b/db.md index 3f7aa80..32aae03 100644 --- a/db.md +++ b/db.md @@ -179,7 +179,7 @@ __По количественному составу__ __По характеристике содержимого__ + _уникальный индекс_ состоит из множества уникальных значений поля; -+ _плотный индекс_ (NoSQL) — индекс, при котором, каждом документе в индексируемой коллекции соответствует запись в индексе, даже если в документе нет индексируемого поля. ++ _плотный индекс_ (NoSQL) — индекс, при котором, каждому документу в индексируемой коллекции соответствует запись в индексе, даже если в документе нет индексируемого поля. + _разреженный индекс_ (NoSQL) — тот, в котором представлены только те документы, для которых индексируемый ключ имеет какое-то определённое значение (существует). + _пространственный индекс_ — оптимизирован для описания географического местоположения. Представляет из себя многоключевой индекс состоящий из широты и долготы. + _составной пространственный индекс_ — индекс, включающий в себя кроме широты и долготы ещё какие-либо мета-данные (например теги). Но географические координаты должны стоять на первом месте. diff --git a/java8.md b/java8.md index 904d885..f430b6a 100644 --- a/java8.md +++ b/java8.md @@ -230,7 +230,7 @@ public static void main(String[] args) { ## Какие виды ссылок на методы вы знаете? + на статический метод; + на метод экземпляра; -+ на конструкторе. ++ на конструктор. [к оглавлению](#java-8) diff --git a/jcf.md b/jcf.md index d856cd9..9e9dcf2 100644 --- a/jcf.md +++ b/jcf.md @@ -883,7 +883,7 @@ __Один__ новый объект статического вложенног [к оглавлению](#java-collections-framework) ## Как перебрать все пары «ключ-значение» в `Map`? -Использовать метод `entrySet()`, который возвращает множество `Set` пар «ключ-значение». +Использовать метод `entrySet()`, который возвращает множество `Set>` пар «ключ-значение». [к оглавлению](#java-collections-framework) diff --git a/jdbc.md b/jdbc.md index 3211f10..56754a6 100644 --- a/jdbc.md +++ b/jdbc.md @@ -190,9 +190,9 @@ __Уровень изолированности транзакций__ — зн Объекты-носители интерфейсов создаются при помощи методов объекта `java.sql.Connection`: -+ `java.sql.createStatement()` возвращает объект _Statement_; -+ `java.sql.prepareStatement()` возвращает объект _PreparedStatement_; -+ `java.sql.prepareCall()` возвращает объект _CallableStatement_; ++ `java.sql.Connection.createStatement()` возвращает объект _Statement_; ++ `java.sql.Connection.prepareStatement()` возвращает объект _PreparedStatement_; ++ `java.sql.Connection.prepareCall()` возвращает объект _CallableStatement_; [к оглавлению](#jdbc) From 5d1c11772e10cb89c1da1ffa0ec99b5719eaec3a Mon Sep 17 00:00:00 2001 From: Anton Shliakhtin Date: Wed, 28 May 2025 09:02:43 +0200 Subject: [PATCH 55/58] Remove duplicate link (#172) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 17ff0b3..472e92e 100644 --- a/README.md +++ b/README.md @@ -834,7 +834,6 @@ + [Top Spring Framework Interview Questions](https://www.baeldung.com/spring-interview-questions) + [Spring Interview Questions](https://www.interviewbit.com/spring-interview-questions/) + [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) -+ [Hibernate Interview Questions](https://www.adaface.com/blog/hibernate-interview-questions/) + [Java Interview Questions](https://labex.io/interview-questions/java) [к оглавлению](#Вопросы-для-собеседования-на-java-developer) From 8c073b3e38ab15ec87f7b290a19cbb72610402a3 Mon Sep 17 00:00:00 2001 From: laptiieff Date: Tue, 3 Mar 2026 18:59:55 +0200 Subject: [PATCH 56/58] Improve answer to composition vs aggregation question in oop.md (#176) --- oop.md | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/oop.md b/oop.md index 8464512..50209c4 100644 --- a/oop.md +++ b/oop.md @@ -363,10 +363,49 @@ __«имеет»__ подразумевает ассоциацию (агрега ## В чем разница между _композицией_ и _агрегацией_? Ассоциация обозначает связь между объектами. Композиция и агрегация — частные случаи ассоциации «часть-целое». -Агрегация предполагает, что объекты связаны взаимоотношением «part-of» (часть). Композиция более строгий вариант агрегации. Дополнительно к требованию «part-of» накладывается условие, что экземпляр «части» может входить только в одно целое (или никуда не входить), в то время как в случае агрегации экземпляр «части» может входить в несколько целых. +_Композиция_ — вложенный объект не может существовать без владельца (владелец создает и уничтожает его): ->Например, книга состоит из страниц, и мы не можем вырвать страницу из книги и вложить в другую книгу. Страницы четко привязаны к конкретной книге, поэтому это композиция. -В тоже время мы можем взять и перенести книгу из одной библиотеки в другую - это уже агрегация. +```java +class Engine { + private final int horsepower; + + Engine(int horsepower) { + this.horsepower = horsepower; + } +} + +class Car { + private final Engine engine; // Engine живёт и умирает вместе с Car + + Car(int horsepower) { + this.engine = new Engine(horsepower); // Car сам создаёт Engine + } +} +``` + +_Агрегация_ — вложенный объект существует независимо, передается извне: + +```java +class Driver { + private final String name; + + Driver(String name) { + this.name = name; + } +} + +class Car { + private Driver driver; // Driver может существовать без Car + + Car(Driver driver) { + this.driver = driver; // Car получает Driver извне + } +} +``` + +Коротко: если `new` внутри класса — композиция, если объект приходит снаружи — агрегация. + +Предпочтительнее использовать агрегацию и внедрять зависимости через конструктор. Это автоматически делает код тестируемым и следует принципу Dependency Inversion из SOLID. Композицию стоит применять, когда есть чёткая причина "спрятать" создание объекта внутрь класса. [к оглавлению](#ООП) From 0698285b0f8a8f3a9ad773e8e10874b372eb8e57 Mon Sep 17 00:00:00 2001 From: Enchased Horse Date: Fri, 26 Jun 2026 10:22:34 +0300 Subject: [PATCH 57/58] Update Placeholder.txt --- images/SQL/Placeholder.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/SQL/Placeholder.txt b/images/SQL/Placeholder.txt index a9b4ab1..8b13789 100644 --- a/images/SQL/Placeholder.txt +++ b/images/SQL/Placeholder.txt @@ -1 +1 @@ -Images for SQL + From 2c3017d4e9d4de03267271f0b134a5a0b878db91 Mon Sep 17 00:00:00 2001 From: Chanov Sergei <73557863+Cair06@users.noreply.github.com> Date: Tue, 4 Aug 2026 10:44:40 +0300 Subject: [PATCH 58/58] Update core.md (#178) --- core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.md b/core.md index f7b6100..bbf189e 100644 --- a/core.md +++ b/core.md @@ -1289,7 +1289,7 @@ public native int hashCode(); [к оглавлению](#java-core) ## Можно ли так реализовать метод `equals(Object that) {return this.hashCode() == that.hashCode()}`? -Строго говоря нельзя, поскольку метод `hashCode()` не гарантирует уникальность значения для каждого объекта. Однако для сравнения экземпляров класса `Object` такой код допустим, т.к. метод `hashCode()` в классе `Object` возвращает уникальные значения для разных объектов (его вычисление основано на использовании алгоритма генерации случайных чисел). +Строго говоря нельзя, поскольку метод `hashCode()` не гарантирует уникальность значения для каждого объекта. Для сравнения экземпляров класса `Object` такой код также недопустим, т.к. стандартный метод `hashCode()` в классе `Object` даже при использовании алгоритма генерации случайных чисел не гарантирует уникальные значения для разных объектов из-за ограниченности диапазона чисел int. [к оглавлению](#java-core)