जैसे java.util.Optional<T>
जावा 8, स्काला के Option[T]
प्रकार के बराबर (कुछ) है , क्या स्काला के समकक्ष है Either[L, R]
?
java.lang.Object
... दुखी।
जैसे java.util.Optional<T>
जावा 8, स्काला के Option[T]
प्रकार के बराबर (कुछ) है , क्या स्काला के समकक्ष है Either[L, R]
?
java.lang.Object
... दुखी।
जवाबों:
कोई भी Either
प्रकार जावा 8 नहीं है, इसलिए आपको खुद को बनाने या किसी तीसरे पक्ष के पुस्तकालय का उपयोग करने की आवश्यकता है।
आप नए Optional
प्रकार का उपयोग करके ऐसी सुविधा का निर्माण कर सकते हैं (लेकिन इस उत्तर के अंत में पढ़ें):
final class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(Optional.of(value), Optional.empty());
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left=l;
right=r;
}
public <T> T map(
Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc)
{
return left.<T>map(lFunc).orElseGet(()->right.map(rFunc).get());
}
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc)
{
return new Either<>(left.map(lFunc),right);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> rFunc)
{
return new Either<>(left, right.map(rFunc));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc)
{
left.ifPresent(lFunc);
right.ifPresent(rFunc);
}
}
उदाहरण उपयोग मामला:
new Random().ints(20, 0, 2).mapToObj(i -> (Either<String,Integer>)(i==0?
Either.left("left value (String)"):
Either.right(42)))
.forEach(either->either.apply(
left ->{ System.out.println("received left value: "+left.substring(11));},
right->{ System.out.println("received right value: 0x"+Integer.toHexString(right));}
));
पूर्वव्यापी में, Optional
आधारित समाधान एक शैक्षणिक उदाहरण की तरह है, लेकिन अनुशंसित दृष्टिकोण नहीं है। एक समस्या null
"खाली" के रूप में है जो "या तो" के अर्थ का विरोध करती है।
निम्न कोड दिखाता है Either
कि null
एक संभावित मूल्य पर विचार करता है, इसलिए यह कड़ाई से "या तो", बाएं या दाएं, भले ही मूल्य है null
:
abstract class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<L,R>() {
@Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return lFunc.apply(value);
}
};
}
public static <L,R> Either<L,R> right(R value) {
return new Either<L,R>() {
@Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return rFunc.apply(value);
}
};
}
private Either() {}
public abstract <T> T map(
Function<? super L, ? extends T> lFunc, Function<? super R, ? extends T> rFunc);
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc) {
return this.<Either<T,R>>map(t -> left(lFunc.apply(t)), t -> (Either<T,R>)this);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> lFunc) {
return this.<Either<L,T>>map(t -> (Either<L,T>)this, t -> right(lFunc.apply(t)));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc) {
map(consume(lFunc), consume(rFunc));
}
private <T> Function<T,Void> consume(Consumer<T> c) {
return t -> { c.accept(t); return null; };
}
}
दोनों फैक्ट्री के तरीकों की शुरुआत में null
केवल एक सख्त अस्वीकृति के साथ इसे बदलना आसान है Objects.requireNonNull(value)
। इसी तरह, खाली के लिए समर्थन जोड़ना या तो कल्पना करना उचित होगा।
Either
, तो टाइप कुछ अर्थ में "बहुत बड़ा" है, क्योंकि आपके left
और right
क्षेत्र दोनों सिद्धांत में खाली हो सकते हैं या दोनों को परिभाषित किया जा सकता है। आपने उन कंस्ट्रक्टरों को छिपा दिया है जो ऐसा संभव कर सकते हैं, लेकिन दृष्टिकोण अभी भी आपके कार्यान्वयन में बग के लिए संभावित है। सरल प्रकार के अंकगणितीय शब्दों में, आप a + b
बाहर निकलने की कोशिश कर रहे हैं (1 + a) * (1 + b)
। ज़रूर, a + b
उस अभिव्यक्ति के परिणाम में होता है, लेकिन ऐसा है 1
और a * b
।
int
संपूर्ण मान श्रेणी का int
उपयोग करते हुए लगभग हर उपयोग के मामले के लिए एक नई "मान्य श्रेणी" प्रकार का आविष्कार करना होगा int
। आखिरकार, Optional
एक ही करता है, वस्तु निर्माण के दौरान आक्रमणकारियों को लागू करना।
Either.left(42).map(left -> null, right -> right)
फेंकता है । इसके अलावा, एक व्यक्ति प्रवर्तन प्रवर्तन को दरकिनार कर सकता है और उत्पादन कर सकता है । या जब एक साथ रखा जाता है, तो फिर से असफल हो जाता है । NoSuchElementException
this.right.get()
Either<empty, empty>
Either.left(42).mapLeft(left -> null)
Either.left(42).mapLeft(left -> null).map(left -> left, right -> right)
Optional.map
फ़ंक्शन को वापस लौटने की अनुमति देता है null
, इसे खाली कर देता है Optional
। हालांकि, इसका पता लगाने और तुरंत फेंकने के अवसर के अलावा, मुझे कोई भी वैकल्पिक समाधान नहीं दिखता है जो "अधिक सही" हो। अफाक, कोई संदर्भ व्यवहार नहीं है, जैसा कि स्काला में है, आप उसका नक्शा नहीं बना सकते null
...
Right
कोड पथ को एक Left
उदाहरण के लिए निष्पादित किया जाए , भले ही त्रुटि समान हो। और हाँ, मैं अभी प्राप्त करने <empty, empty>
और बाद में विफल होने के बजाय तुरंत विफल होना पसंद करूंगा । लेकिन फिर, यह सब सिर्फ एक स्वाद / शैली की बात है।
एटलसियन फुगे देखें । वहां का अच्छा कार्यान्वयन है Either
।
जावा मानक पुस्तकालय में कोई भी नहीं है। लेकिन वहाँ के एक कार्यान्वयन है या तो में FunctionalJava , कई अन्य अच्छा कक्षाओं के साथ।
साइक्लोप्स-रिएक्शन में एक 'सही' पक्षपाती या तो कार्यान्वयन है जिसे एक्सोर कहा जाता है ।
Xor.primary("hello")
.map(s->s+" world")
//Primary["hello world"]
Xor.secondary("hello")
.map(s->s+" world")
//Secondary["hello"]
Xor.secondary("hello")
.swap()
.map(s->s+" world")
//Primary["hello world"]
Xor.accumulateSecondary(ListX.of(Xor.secondary("failed1"),
Xor.secondary("failed2"),
Xor.primary("success")),
Semigroups.stringConcat)
//failed1failed2
एक संबंधित प्रकार Ior भी है जो या तो tuple2 के रूप में कार्य कर सकता है।
Xor
था नाम दिया करने के लिए Either
: साइक्लोप्स एक्स में static.javadoc.io/com.oath.cyclops/cyclops/10.0.0-FINAL/cyclops/...
नहीं, कोई नहीं है।
जावा भाषा डेवलपर्स स्पष्ट रूप से बताते हैं कि जैसे प्रकार का Option<T>
उपयोग केवल अस्थायी मूल्यों के रूप में किया जाता है (उदाहरण के लिए स्ट्रीम संचालन परिणाम), इसलिए जब वे अन्य भाषाओं की तरह ही होते हैं, तो उनका उपयोग नहीं किया जाता है क्योंकि वे अन्य में उपयोग किए जाते हैं भाषाएँ। इसलिए यह आश्चर्य की बात नहीं है कि ऐसा कुछ भी नहीं है Either
क्योंकि यह स्वाभाविक रूप से उत्पन्न नहीं होता है (जैसे धारा संचालन से) Optional
।
Either
स्वाभाविक रूप से पैदा होता है। शायद मैं गलत कर रहा हूं। जब कोई विधि दो अलग-अलग चीजों को वापस कर सकती है तो आप क्या करते हैं? की तरह Either<List<String>, SomeOtherClass>
?
Either
एक छोटे से पुस्तकालय में एक अकेला कार्यान्वयन है , "महत्वाकांक्षा": http://github.com/poetix/ambivalence
आप इसे मावेन केंद्रीय से प्राप्त कर सकते हैं:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
लैम्ब्डा-साथी का एक Either
प्रकार है (और कुछ अन्य कार्यात्मक प्रकार जैसे Try
)
<dependency>
<groupId>no.finn.lambda</groupId>
<artifactId>lambda-companion</artifactId>
<version>0.25</version>
</dependency>
इसका उपयोग करना आसान है:
final String myValue = Either.right("example").fold(failure -> handleFailure(failure), Function.identity())