क्या जावा 8 में स्काला के समान है?


81

जैसे java.util.Optional<T>जावा 8, स्काला के Option[T]प्रकार के बराबर (कुछ) है , क्या स्काला के समकक्ष है Either[L, R]?


इस समय के बाद भी कोई मानक कार्यान्वयन नहीं :(
चेरी

हमेशा होता है java.lang.Object ... दुखी।
एलेक्स आर।

जवाबों:


68

कोई भी 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)। इसी तरह, खाली के लिए समर्थन जोड़ना या तो कल्पना करना उचित होगा।


11
ध्यान रखें कि जब यह व्यवहार करता है Either, तो टाइप कुछ अर्थ में "बहुत बड़ा" है, क्योंकि आपके leftऔर rightक्षेत्र दोनों सिद्धांत में खाली हो सकते हैं या दोनों को परिभाषित किया जा सकता है। आपने उन कंस्ट्रक्टरों को छिपा दिया है जो ऐसा संभव कर सकते हैं, लेकिन दृष्टिकोण अभी भी आपके कार्यान्वयन में बग के लिए संभावित है। सरल प्रकार के अंकगणितीय शब्दों में, आप a + bबाहर निकलने की कोशिश कर रहे हैं (1 + a) * (1 + b)। ज़रूर, a + bउस अभिव्यक्ति के परिणाम में होता है, लेकिन ऐसा है 1और a * b
मिस्टीरियस डैन

6
@ मिस्टीरियस डैन: ऑब्जेक्ट कंस्ट्रक्शन के दौरान कुछ खास तरह के स्टेट्स को वर्जित करना जावा में पसंदीदा तरीका है। अन्यथा आपको एक उदाहरण के रूप में, एक चर का उपयोग करते समय intसंपूर्ण मान श्रेणी का intउपयोग करते हुए लगभग हर उपयोग के मामले के लिए एक नई "मान्य श्रेणी" प्रकार का आविष्कार करना होगा int। आखिरकार, Optionalएक ही करता है, वस्तु निर्माण के दौरान आक्रमणकारियों को लागू करना।
होल्गर

1
@ होलर: (गलत) पर ( सही) Either.left(42).map(left -> null, right -> right)फेंकता है । इसके अलावा, एक व्यक्ति प्रवर्तन प्रवर्तन को दरकिनार कर सकता है और उत्पादन कर सकता है । या जब एक साथ रखा जाता है, तो फिर से असफल हो जाता है । NoSuchElementExceptionthis.right.get()Either<empty, empty>Either.left(42).mapLeft(left -> null)Either.left(42).mapLeft(left -> null).map(left -> left, right -> right)
चार्ली

2
@charlie: यह समाधान यह नहीं मानता है कि Optional.mapफ़ंक्शन को वापस लौटने की अनुमति देता है null, इसे खाली कर देता है Optional। हालांकि, इसका पता लगाने और तुरंत फेंकने के अवसर के अलावा, मुझे कोई भी वैकल्पिक समाधान नहीं दिखता है जो "अधिक सही" हो। अफाक, कोई संदर्भ व्यवहार नहीं है, जैसा कि स्काला में है, आप उसका नक्शा नहीं बना सकते null...
होल्गर

1
@ होलगर: मैं मानता हूं कि कोई "अधिक सही" तरीका नहीं है, मुझे सिर्फ यह पसंद नहीं था कि Rightकोड पथ को एक Leftउदाहरण के लिए निष्पादित किया जाए , भले ही त्रुटि समान हो। और हाँ, मैं अभी प्राप्त करने <empty, empty>और बाद में विफल होने के बजाय तुरंत विफल होना पसंद करूंगा । लेकिन फिर, यह सब सिर्फ एक स्वाद / शैली की बात है।
चार्ली

26

लेखन के समय, vavr (पूर्व में javaslang) संभवतः सबसे लोकप्रिय कार्यात्मक जावा 8 पुस्तकालय है। यह मेरे अन्य उत्तर में लैम्बडा-साथी के ईयर के समान है।

Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();

23

एटलसियन फुगे देखें । वहां का अच्छा कार्यान्वयन है Either


1
DATE का लिंक: bitbucket.org/atlassian/fugue/src/master/fugue/src/main/java/io/… एटलसियन ने एक या दो साल पहले एक नेमस्पेस कांटा लगाया था। आप io नाम स्थान चाहते हैं
कीनन

17

जावा मानक पुस्तकालय में कोई भी नहीं है। लेकिन वहाँ के एक कार्यान्वयन है या तो में FunctionalJava , कई अन्य अच्छा कक्षाओं के साथ।


या तो लिंक को हटा दिया गया लगता है। क्या आप सुनिश्चित हैं कि परियोजना अभी भी समर्थित है?
फ्लेम_फिनिक्स

मैंने लिंक को अपडेट कर दिया है। परियोजना को अभी भी सक्रिय रूप से AFAIK बनाए रखा जा रहा है।
रवि किरण

यह है, लेकिन प्रलेखन abysmal है। :(
मिशा तवक्लिदेज़

10

साइक्लोप्स-रिएक्शन में एक 'सही' पक्षपाती या तो कार्यान्वयन है जिसे एक्सोर कहा जाता है ।

 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 के रूप में कार्य कर सकता है।

  • प्रकटीकरण मैं cyclops- प्रतिक्रिया का लेखक हूं।

3
Xorथा नाम दिया करने के लिए Either: साइक्लोप्स एक्स में static.javadoc.io/com.oath.cyclops/cyclops/10.0.0-FINAL/cyclops/...
seanf

6

नहीं, कोई नहीं है।

जावा भाषा डेवलपर्स स्पष्ट रूप से बताते हैं कि जैसे प्रकार का Option<T>उपयोग केवल अस्थायी मूल्यों के रूप में किया जाता है (उदाहरण के लिए स्ट्रीम संचालन परिणाम), इसलिए जब वे अन्य भाषाओं की तरह ही होते हैं, तो उनका उपयोग नहीं किया जाता है क्योंकि वे अन्य में उपयोग किए जाते हैं भाषाएँ। इसलिए यह आश्चर्य की बात नहीं है कि ऐसा कुछ भी नहीं है Eitherक्योंकि यह स्वाभाविक रूप से उत्पन्न नहीं होता है (जैसे धारा संचालन से) Optional


8
क्या आपके पास उस पर एक स्रोत है?
Cannoliopsida

3
@akroy, यह सही प्रतीत होता है, ब्रायन गोएत्ज़ ने इस उत्तर में बहुत कुछ लिखा: लिंक
रॉनीहै

2
मेरे लिए Eitherस्वाभाविक रूप से पैदा होता है। शायद मैं गलत कर रहा हूं। जब कोई विधि दो अलग-अलग चीजों को वापस कर सकती है तो आप क्या करते हैं? की तरह Either<List<String>, SomeOtherClass>?
tamas.kenez

3
मुझे इस बात पर भी आपत्ति होगी कि या तो स्वाभाविक रूप से मेरे लिए उत्पन्न होता है, मेरे लिए एक धारा में जहां एक मानचित्र संचालन संभावित रूप से एक अपवाद को फेंक सकता है, इसलिए मैं या तो <स्ट्रीम के परिणाम के लिए मैप करता हूं <अपवाद, परिणाम>
ओलिवियर गेयार्डिन

6

Eitherएक छोटे से पुस्तकालय में एक अकेला कार्यान्वयन है , "महत्वाकांक्षा": http://github.com/poetix/ambivalence

आप इसे मावेन केंद्रीय से प्राप्त कर सकते हैं:

<dependency>
    <groupId>com.codepoetics</groupId>
    <artifactId>ambivalence</artifactId>
    <version>0.2</version>
</dependency>

5

लैम्ब्डा-साथी का एक 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())

1
परियोजना अब रखरखाव के अधीन नहीं है।
ज्वाला_पुनिक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.