কেন এই জাভা 8 ল্যাম্বদা সংকলন করতে ব্যর্থ হয়?


85

নিম্নলিখিত জাভা কোডটি সংকলন করতে ব্যর্থ:

@FunctionalInterface
private interface BiConsumer<A, B> {
    void accept(A a, B b);
}

private static void takeBiConsumer(BiConsumer<String, String> bc) { }

public static void main(String[] args) {
    takeBiConsumer((String s1, String s2) -> new String("hi")); // OK
    takeBiConsumer((String s1, String s2) -> "hi"); // Error
}

সংকলক রিপোর্ট:

Error:(31, 58) java: incompatible types: bad return type in lambda expression
    java.lang.String cannot be converted to void

অদ্ভুত বিষয়টি হ'ল লাইনটি "ওকে" চিহ্নিত করে সূক্ষ্ম সংকলন করে, তবে "ত্রুটি" চিহ্নিত লাইনটি ব্যর্থ হয়। এগুলি মূলত অভিন্ন বলে মনে হয়।


4
এটি এখানে একটি টাইপ যে কার্যকরী ইন্টারফেস পদ্ধতি বাতিল বাতিল?
নাথান হিউজেস

6
পুনঃটুইট এটি প্রশ্নের কেন্দ্রে পরিণত হয়েছে- গৃহীত উত্তর দেখুন।
ব্রায়ান গর্ডন

সেখানে ভিতরে কোড হতে হবে { }এর takeBiConsumer... আর তাই যদি আপনি একটি উদাহরণ দিতে পারা ... যদি আমি এই সঠিকভাবে পড়া, bcবর্গ / ইন্টারফেসের একটি দৃষ্টান্ত হল BiConsumer, এবং এইভাবে একটি পদ্ধতি নামক থাকা উচিত acceptইন্টারফেস স্বাক্ষর মেলে। .. ... এবং যদি এটি সঠিক হয়, তবে acceptপদ্ধতিটি কোথাও সংজ্ঞায়িত করা দরকার (উদাহরণস্বরূপ এমন একটি শ্রেণি যা ইন্টারফেসটি প্রয়োগ করে) ... তাই কি হবে যা {}?? ... ... ... ধন্যবাদ
dsdsdsddd

একক পদ্ধতির সাথে ইন্টারফেসগুলি জাভা ৮ এ (String s1, String s2) -> "hi"ল্যাম্বডাসের সাথে বিনিময়যোগ্য are এই ক্ষেত্রে, বায়কনসুমার <স্ট্রিং, স্ট্রিং> এর উদাহরণ।
ব্রায়ান গর্ডন

উত্তর:


100

আপনার ল্যাম্বদা একত্রে হওয়া দরকার BiConsumer<String, String>। যদি আপনি জেএলএস # 15.27.3 দেখুন (একটি ল্যাম্বদার প্রকার) :

নীচের সমস্তগুলি সত্য হলে একটি ল্যাম্বডা এক্সপ্রেশন ফাংশনের ধরণের সাথে একত্রিত হয়:

  • [...]
  • যদি ফাংশনের ধরণের ফলাফলটি অকার্যকর হয় তবে ল্যাম্বডা বডি হয় স্টেটমেন্ট এক্সপ্রেশন (§14.8) বা শূন্য-সামঞ্জস্যপূর্ণ ব্লক।

সুতরাং ল্যাম্বডা অবশ্যই স্টেটমেন্ট এক্সপ্রেশন বা শূন্য সামঞ্জস্যপূর্ণ ব্লক হওয়া উচিত:


31
@ ব্রায়ান গর্ডন একটি স্ট্রিং আক্ষরিক একটি অভিব্যক্তি (সুনির্দিষ্ট হতে একটি ধ্রুবক প্রকাশ) তবে বিবৃতি প্রকাশ নয় expression
Assylias

44

Basicly, new String("hi")কোডের একটি এক্সিকিউটেবল টুকরা যে আসলে কিছু নেই (এটি একটি নতুন স্ট্রিং তৈরি করে এবং তারপর এটি ফেরৎ) হয়। প্রত্যাবর্তিত মানটিকে অগ্রাহ্য করা যায় এবং new String("hi")এখনও একটি নতুন স্ট্রিং তৈরি করতে শূন্য-রিটার্ন ল্যাম্বডায় ব্যবহার করা যেতে পারে ।

তবে, "hi"এটি কেবল একটি ধ্রুবক যা নিজে থেকে কিছু করে না। ল্যাম্বডা দেহে এটির সাথে একমাত্র যুক্তিযুক্ত জিনিসটি এটি ফিরিয়ে দেওয়া । তবে ল্যাম্বদা পদ্ধতিতে রিটার্ন টাইপ থাকতে হবে Stringবা Object, তবে এটি ফিরে আসে void, সুতরাং String cannot be casted to voidত্রুটি।


6
সঠিক আনুষ্ঠানিক শব্দটি হ'ল এক্সপ্রেশন স্টেটমেন্ট , উদাহরণস্বরূপ সৃষ্টি অভিব্যক্তি উভয় জায়গায় উপস্থিত হতে পারে, যেখানে একটি অভিব্যক্তি বা যেখানে একটি বিবৃতি প্রয়োজন, যখন একটি Stringআক্ষরিক কেবল একটি অভিব্যক্তি যা বিবৃতি প্রসঙ্গে ব্যবহার করা যায় না ।
হোলার

4
গৃহীত উত্তরটি আনুষ্ঠানিকভাবে সঠিক হতে পারে তবে
এটির

4
@ এডসি 65: এ কারণেই এই উত্তরটিও আপলোড হয়েছে। নিয়মের যুক্তি এবং অপ্রাতিষ্ঠানিক স্বজ্ঞাত ব্যাখ্যাটি সত্যই সহায়তা করতে পারে তবে যাইহোক, প্রতিটি প্রোগ্রামারকে সচেতন হওয়া উচিত যে এর পিছনে আনুষ্ঠানিক বিধি রয়েছে এবং যে ক্ষেত্রে আনুষ্ঠানিক নিয়মের ফলাফল স্বজ্ঞাতভাবে বোঝা যায় না , আনুষ্ঠানিক নিয়মটি এখনও জিতবে । যেমন ()->x++আইনী, যদিও ()->(x++)মূলত ঠিক একই কাজ করা, তা নয় ...
হোলগার

21

প্রথম কেসটি ঠিক আছে কারণ আপনি একটি "বিশেষ" পদ্ধতি (একজন নির্মাতা) প্রার্থনা করছেন এবং আপনি আসলে তৈরি বস্তুটি নিচ্ছেন না। কেবল এটি আরও পরিষ্কার করার জন্য, আমি আপনার ল্যাম্বডাসে alচ্ছিক বন্ধনীগুলি রাখব:

takeBiConsumer((String s1, String s2) -> {new String("hi");}); // OK
takeBiConsumer((String s1, String s2) -> {"hi"}); // Error

এবং আরও পরিষ্কার, আমি এটি পুরানো স্বরলিপিটিতে অনুবাদ করব:

takeBiConsumer(new BiConsumer<String, String>(String s1, String s2) {
    public void accept(String s, String s2) {
        new String("hi"); // OK
    }
});

takeBiConsumer(new BiConsumer<String, String>(String s1, String s2) {
    public void accept(String s, String s2) {
        "hi"; // Here, the compiler will attempt to add a "return"
              // keyword before the "hi", but then it will fail
              // with "compiler error ... bla bla ...
              //  java.lang.String cannot be converted to void"
    }
});

প্রথম ক্ষেত্রে আপনি একটি নির্মাতা কার্যকর করছেন, তবে আপনি তৈরি বস্তুটি ফিরিয়ে দিচ্ছেন না, দ্বিতীয় ক্ষেত্রে আপনি একটি স্ট্রিং মান ফেরানোর চেষ্টা করছেন, তবে আপনার ইন্টারফেসে আপনার পদ্ধতিটি BiConsumerশূন্য হয়ে যায়, তাই সংকলক ত্রুটি।


12

জেএলএস এটি নির্দিষ্ট করে

যদি ফাংশনের ধরণের ফলাফলটি অকার্যকর হয় তবে ল্যাম্বডা বডি হয় স্টেটমেন্ট এক্সপ্রেশন (§14.8) বা শূন্য-সামঞ্জস্যপূর্ণ ব্লক।

এখন এটি বিস্তারিতভাবে দেখুন,

যেহেতু আপনার takeBiConsumerপদ্ধতিটি অকার্যকর, তাই ল্যাম্বদা প্রাপ্তি new String("hi")এটিকে একটি ব্লকের মতো ব্যাখ্যা করবে

{
    new String("hi");
}

যা একটি শূন্য বৈধ, তাই প্রথম ক্ষেত্রে সংকলন।

যাইহোক, ল্যাম্বডা যেখানে ক্ষেত্রে -> "hi"একটি ব্লক

{
    "hi";
}

জাভাতে বৈধ সিনট্যাক্স নয়। সুতরাং "হাই" এর সাথে একমাত্র কাজটি হ'ল চেষ্টা করে ফিরে আসা।

{
    return "hi";
}

যা বাতিল হয়ে যায় না এবং ত্রুটির বার্তাটি ব্যাখ্যা করে

incompatible types: bad return type in lambda expression
    java.lang.String cannot be converted to void

ভাল করে বুঝতে, নোট জন্য যে আপনি যদি ধরণ পরিবর্তন takeBiConsumerএকটি স্ট্রিং, -> "hi"যেমন কেবল সরাসরি স্ট্রিং ফিরে যাওয়ার চেষ্টা করবে কার্যকর থাকবে।


মনে রাখবেন যে প্রথমে আমি ভেবেছিলাম ল্যাম্বডা ভুল দাওয়াত প্রসঙ্গে থাকার কারণে ত্রুটিটি হয়েছিল, তাই আমি এই সম্ভাবনাটি সম্প্রদায়ের সাথে ভাগ করে নিচ্ছি:

জেএলএস 15.27

যদি একটি ল্যাম্বডা এক্সপ্রেশনটি অ্যাসাইনমেন্ট প্রসঙ্গ (§5.2), একটি অনুরোধ প্রসঙ্গ (§5.3), বা ingালাই প্রসঙ্গে (context5.5) ব্যতীত অন্য কোথাও কোনও প্রোগ্রামে ঘটে তবে এটি একটি সংকলন-সময় ত্রুটি।

তবে আমাদের ক্ষেত্রে, আমরা একটি অনুরোধ প্রসঙ্গে যা সঠিক।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.