জাভা 8: ল্যাম্বদা-স্ট্রিমস, ব্যতিক্রম সহ পদ্ধতি দ্বারা ফিল্টার


168

আমি সাধারণত এটা কাজ করে জরিমানা জাভা 8. এর ল্যামডা এক্সপ্রেশন আউট হওয়ার সময় একটি সমস্যা আছে, কিন্তু এখন আমি পদ্ধতি আছে যে নিক্ষেপ IOException's। আপনি নীচের কোডটি দেখলে এটি সেরা:

class Bank{
    ....
    public Set<String> getActiveAccountNumbers() throws IOException {
        Stream<Account> s =  accounts.values().stream();
        s = s.filter(a -> a.isActive());
        Stream<String> ss = s.map(a -> a.getNumber());
        return ss.collect(Collectors.toSet());
    }
    ....
}

interface Account{
    ....
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
    ....
}

সমস্যাটি হ'ল এটি সংকলন করে না, কারণ আমাকে isAtive- এবং getNumber-Methods এর সম্ভাব্য ব্যতিক্রমগুলি ধরতে হবে। তবে আমি নীচের মতো স্পষ্টভাবে চেষ্টা-ধরা-ব্লক ব্যবহার করলেও এটি সংকলন করে না কারণ আমি ব্যতিক্রমটি ধরি না। সুতরাং হয় জেডিকেতে একটি বাগ আছে, বা এই ব্যতিক্রমগুলি কীভাবে ধরতে হয় তা আমি জানি না।

class Bank{
    ....
    //Doesn't compile either
    public Set<String> getActiveAccountNumbers() throws IOException {
        try{
            Stream<Account> s =  accounts.values().stream();
            s = s.filter(a -> a.isActive());
            Stream<String> ss = s.map(a -> a.getNumber());
            return ss.collect(Collectors.toSet());
        }catch(IOException ex){
        }
    }
    ....
}

আমি কীভাবে এটি কাজ করতে পারি? কেউ আমাকে সঠিক সমাধানের ইঙ্গিত দিতে পারে?




4
সহজ এবং সঠিক উত্তর: ল্যাম্বদার ভিতরে ব্যতিক্রমটি ধরুন।
ব্রায়ান গয়েটজ

উত্তর:


211

ল্যাম্বডাটি পালানোর আগে আপনাকে অবশ্যই এই ব্যতিক্রমটি ধরতে হবে :

s = s.filter(a -> { try { return a.isActive(); } 
                    catch (IOException e) { throw new UncheckedIOException(e); }}});

এই বিষয়টি বিবেচনা করুন যে লাম্বদাটি আপনি যে জায়গায় লিখেছেন তা নির্ধারণ করা হয় না, তবে কোনও জেডিকে বর্গের মধ্যে কিছু সম্পূর্ণ অপ্রাসঙ্গিক জায়গায়। সুতরাং এটি সেই বিন্দু যেখানে সেই পরীক্ষিত ব্যতিক্রমটি নিক্ষেপ করা হবে এবং সেই জায়গায় এটি ঘোষণা করা হয়নি।

আপনি আপনার ল্যাম্বডা এর একটি মোড়ক ব্যবহার করে এটি মোকাবেলা করতে পারেন যা চেক করা ব্যতিক্রমগুলি চেক না করাগুলিতে অনুবাদ করে:

public static <T> T uncheckCall(Callable<T> callable) {
  try { return callable.call(); }
  catch (RuntimeException e) { throw e; }
  catch (Exception e) { throw new RuntimeException(e); }
}

আপনার উদাহরণ হিসাবে লেখা হবে

return s.filter(a -> uncheckCall(a::isActive))
        .map(Account::getNumber)
        .collect(toSet());

আমার প্রকল্পগুলিতে আমি মোড়ক ছাড়াই এই সমস্যাটি মোকাবেলা করি; পরিবর্তে আমি একটি পদ্ধতি ব্যবহার করি যা ব্যতিক্রমগুলির সংকলকটির চেকিং কার্যকরভাবে অক্ষম করে। বলা বাহুল্য, এটি যত্ন সহকারে পরিচালনা করা উচিত এবং প্রকল্পের প্রত্যেককে অবশ্যই সচেতন হতে হবে যে যেখানে এটি ঘোষণা করা হয়নি সেখানে একটি পরীক্ষিত ব্যতিক্রম উপস্থিত হতে পারে। এটি নদীর গভীরতানির্ণয় কোড:

public static <T> T uncheckCall(Callable<T> callable) {
  try { return callable.call(); }
  catch (Exception e) { return sneakyThrow(e); }
}
public static void uncheckRun(RunnableExc r) {
  try { r.run(); } catch (Exception e) { sneakyThrow(e); }
}
public interface RunnableExc { void run() throws Exception; }


@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

এবং আপনি IOExceptionএটি আপনার মুখে ছুঁড়ে ফেলার আশা করতে পারেন , যদিও collectএটি ঘোষণা করে না। ইন সবচেয়ে কিন্তু সব বাস্তব জীবনের ক্ষেত্রে আপনি শুধু ব্যতিক্রম যাহাই হউক না কেন rethrow, এবং একটি জেনেরিক ব্যর্থতা যেমন হ্যান্ডেল করতে চাইবেন। এই সমস্ত ক্ষেত্রে, কিছুই স্পষ্টতা বা নির্ভুলতায় হারিয়ে যায় না। কেবল সেই সমস্ত অন্যান্য ক্ষেত্রেই সাবধান থাকুন, যেখানে আপনি ঘটনাস্থলে ব্যতিক্রমটি করতে চাইবেন। সংস্থাপক দ্বারা বিকাশকারীকে সচেতন করা হবে না যে সেখানে IOExceptionধরা পড়ার একটি আছে এবং সংকলক প্রকৃতপক্ষে অভিযোগ করবে যদি আপনি এটি ধরার চেষ্টা করেন কারণ আমরা এটিকে বিশ্বাস করে বোকা বানিয়েছি যে এইরকম কোনও ব্যতিক্রম ছোঁড়া যায় না।


4
আমি নেটটিআইওকে এর আগে "স্নিগ্ধ থ্রো" করতে দেখেছি এবং আমি আমার চেয়ারটি জানালা দিয়ে ফেলে দিতে চেয়েছিলাম। "কি? এই চেক করা ব্যতিক্রমটি কোথা থেকে ফাঁস হয়েছে?" আমি এখনও দেখা স্নিগ্ধ থ্রো এর প্রথম বৈধ ব্যবহারের কেস। একটি প্রোগ্রামার হিসাবে আপনি স্নিগ্ধ নিক্ষেপ ইঙ্গিত সম্ভব সম্পর্কে সচেতন হতে হবে। সম্ভবত আরও ভাল কি কেবল অন্য স্ট্রিম ইন্টারফেস / ইমপ্লিট তৈরি করা যা পরীক্ষিত ব্যতিক্রমকে সমর্থন করে?
কেভিনার্পে

8
কোনও বুদ্ধিমান এপিআই এর ক্লায়েন্টের কাছে অঘোষিত চেক করা ব্যতিক্রমগুলি সরবরাহ করা উচিত নয়, এটি নিশ্চিত। এপিআই-এর মধ্যে একটি বোঝাপড়া হতে পারে, যদিও সেই চেক করা ব্যতিক্রম ফাঁস হতে পারে। এগুলি ততক্ষণ ক্ষতি সাধন করে না যতক্ষণ না তারা সাধারণ ব্যর্থতার অন্য একটি চিহ্ন এবং তারা ধরা পড়ে এবং পাইকারিভাবে পরিচালিত হতে চলেছে।
মার্কো তোপোলনিক

5
@ কেভিনার্পে হুবুহু নিক্ষেপ করা একটি খারাপ ধারণা এটি সঠিক কারণ। সংক্ষেপক সংক্ষিপ্ত বিবরণ ভবিষ্যতের রক্ষণাবেক্ষণকারীদের বিভ্রান্ত করতে বাধ্য।
থরবজর্ন রাভন অ্যান্ডারসন

29
আপনি নিয়মগুলি পছন্দ করেন না বলেই আইনটিকে নিজের হাতে নেওয়া কোনও ভাল ধারণা নয়। আপনার পরামর্শটি দায়িত্বজ্ঞানহীন, কারণ এটি প্রোগ্রামের স্বচ্ছতা এবং রক্ষণাবেক্ষণের জন্য আরও অনেক গুরুত্বপূর্ণ বিবেচনার চেয়ে কোড লেখকের সুবিধাকে দেয়।
ব্রায়ান গয়েটজ

34
@ ব্রায়ান কেবল যেহেতু কোনও কিছু নিয়ম হওয়ার অর্থ এটি ভাল ধারণা নয়। তবে আমি অবাক হয়েছি যে আপনি আমার উত্তরের দ্বিতীয় অংশটিকে "পরামর্শ" হিসাবে উল্লেখ করেছেন, যেহেতু আমি ভেবেছিলাম যে সমাধান হিসাবে আমি কী প্রস্তাব করেছি এবং আগ্রহী পাঠকের কাছে এফওয়াইআই হিসাবে আমি যে অফার দিচ্ছি তা প্রজ্ঞা অস্বীকারকারীদের সাথে প্রকাশ করেছি।
মার্কো টপলনিক

29

আপনি লম্বডাস দিয়ে আপনার স্থির ব্যথাও প্রচার করতে পারেন, তাই পুরো জিনিসটি পঠনযোগ্য বলে মনে হচ্ছে:

s.filter(a -> propagate(a::isActive))

propagateএখানে java.util.concurrent.Callableপ্যারামিটার হিসাবে প্রাপ্ত হয় এবং কল চলাকালীন যে কোনও ব্যতিক্রম রূপান্তরিত হয় RuntimeException। পেয়ারা তে একটি অনুরূপ রূপান্তর পদ্ধতি থ্রোয়েবলস # প্রচার (থ্রোয়েবল) রয়েছে।

ল্যাম্বডা পদ্ধতিতে শৃঙ্খলার জন্য এই পদ্ধতিটি অপরিহার্য বলে মনে হচ্ছে, তাই আমি আশা করি একদিন এটি জনপ্রিয় একটি তালিকায় যুক্ত হবে বা এই প্রচারমূলক আচরণটি ডিফল্টরূপে হবে।

public class PropagateExceptionsSample {
    // a simplified version of Throwables#propagate
    public static RuntimeException runtime(Throwable e) {
        if (e instanceof RuntimeException) {
            return (RuntimeException)e;
        }

        return new RuntimeException(e);
    }

    // this is a new one, n/a in public libs
    // Callable just suits as a functional interface in JDK throwing Exception 
    public static <V> V propagate(Callable<V> callable){
        try {
            return callable.call();
        } catch (Exception e) {
            throw runtime(e);
        }
    }

    public static void main(String[] args) {
        class Account{
            String name;    
            Account(String name) { this.name = name;}

            public boolean isActive() throws IOException {
                return name.startsWith("a");
            }
        }


        List<Account> accounts = new ArrayList<>(Arrays.asList(new Account("andrey"), new Account("angela"), new Account("pamela")));

        Stream<Account> s = accounts.stream();

        s
          .filter(a -> propagate(a::isActive))
          .map(a -> a.name)
          .forEach(System.out::println);
    }
}

22

এই UtilExceptionসহায়ক শ্রেণিটি আপনাকে জাভা স্ট্রিমগুলিতে যেকোনো চেক করা ব্যতিক্রমগুলি ব্যবহার করতে দেয়:

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

নোট Class::forNameনিক্ষেপ ClassNotFoundException, যা চেক করা হয় । স্ট্রিমটি নিজেও ছুঁড়েছে ClassNotFoundException, এবং কিছু মোড়ানো চেক করা ব্যতিক্রম নয়।

public final class UtilException {

@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }

@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }

@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
    R apply(T t) throws E;
    }

@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
    T get() throws E;
    }

@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }

/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
    return t -> {
        try { return function.apply(t); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }

/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }

}

এটি কীভাবে ব্যবহার করবেন সে সম্পর্কে আরও অনেক উদাহরণ (স্থিতিশীলভাবে আমদানির পরে UtilException):

@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }

@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1
          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2
          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }

@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }

@Test    
public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }

@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }

তবে নিম্নলিখিত সুবিধা, অসুবিধাগুলি এবং সীমাবদ্ধতাগুলি বোঝার আগে এটি ব্যবহার করবেন না :

The যদি কলিং-কোডটি চেক করা ব্যতিক্রমটি পরিচালনা করতে হয় তবে আপনি এটি স্ট্রিমযুক্ত পদ্ধতির থ্রোস ক্লোজে যুক্ত করতে হবে। সংকলকটি আপনাকে এটি আর যুক্ত করতে বাধ্য করবে না, তাই এটি ভুলে যাওয়া সহজ।

The যদি কলিং-কোডটি ইতিমধ্যে চেক করা ব্যতিক্রমগুলি পরিচালনা করে তবে সংকলকটি আপনাকে স্ট্রিমটি সম্বলিত পদ্ধতি ঘোষণায় থ্রোস ক্লজ যুক্ত করার জন্য স্মরণ করিয়ে দেবে (যদি আপনি এটি বলেন না যে: ব্যতিক্রমটি সংশ্লিষ্ট চেষ্টা স্টেটমেন্টের শিরোনামে কখনও ছুঁড়ে দেওয়া হয় না) )।

Case যে কোনও ক্ষেত্রে, আপনি পরীক্ষা করা ব্যতিক্রমটি ধরতে স্ট্রিমের চারপাশে নিজেকে ঘিরে রাখতে সক্ষম হবেন না the যে স্ট্রিমটি রয়েছে সেই পদ্ধতিতে (যদি আপনি চেষ্টা করেন, সংকলকটি বলবে: ব্যতিক্রমটি সংশ্লিষ্ট চেষ্টা বিবৃতিতে কোনও দিনই ছোঁড়া হয় না)।

You আপনি যদি এমন কোনও পদ্ধতিতে কল করছেন যা আক্ষরিকরূপে এটি যে ব্যতিক্রম ঘোষণা করে তা কখনই ফেলতে পারে না, তবে আপনার থ্রো ক্লজটি অন্তর্ভুক্ত করা উচিত নয়। উদাহরণস্বরূপ: নতুন স্ট্রিং (বাইটআরআর, "ইউটিএফ -8") অসমর্থিত এনকোডিংএক্সসেপশন ছুঁড়েছে, তবে ইউটিএফ -8 সর্বদা উপস্থিত থাকার জন্য জাভা স্পেস দ্বারা গ্যারান্টিযুক্ত। এখানে, থ্রো ডিক্লোরেশনটি একটি উপদ্রব এবং এটি ন্যূনতম বয়লারপ্লেট দিয়ে চুপ করার কোনও সমাধান স্বাগত।

You আপনি যদি চেক করা ব্যতিক্রমগুলি ঘৃণা করেন এবং মনে করেন যে এগুলি শুরু করার জন্য জাভা ভাষার সাথে আর যুক্ত করা উচিত নয় (ক্রমবর্ধমান সংখ্যক লোকেরা এইভাবে মনে করেন, এবং আমি তাদের মধ্যে কেউ নই), তবে কেবলমাত্র চেক করা ব্যতিক্রমটি যুক্ত করবেন না স্ট্রিম রয়েছে এমন পদ্ধতির ধারাটি ছুড়ে ফেলে। চেক করা ব্যতিক্রমগুলি তখন একটি চেক করা ব্যতিক্রমের মতো আচরণ করবে।

You আপনি যদি একটি কঠোর ইন্টারফেস প্রয়োগ করছেন যেখানে আপনার কাছে ছোঁড়া ঘোড়া ঘোষণার যোগ করার বিকল্প নেই, এবং এখনও একটি ব্যতিক্রম ছুঁড়ে দেওয়া সম্পূর্ণ উপযুক্ত, তবে কেবল নিক্ষিপ্ত ব্যতিক্রমগুলি স্ট্যাকট্রেসে ফলাফল ছুঁড়ে ফেলার অধিকার অর্জনের জন্য একটি ব্যতিক্রম মোড়ানো pping যা আসলে কী ভুল হয়েছে সে সম্পর্কে কোনও তথ্য অবদান রাখে না। একটি ভাল উদাহরণ রান্নেবল.আরুন (), যা কোনও পরীক্ষিত ব্যতিক্রম ছুঁড়ে না ফেলে। এই ক্ষেত্রে, আপনি স্ট্রিম রয়েছে এমন পদ্ধতির থ্রো ক্লজে চেক করা ব্যতিক্রমটি যুক্ত না করার সিদ্ধান্ত নিতে পারেন।

Any যে কোনও ক্ষেত্রে, আপনি যদি স্ট্রিম রয়েছে এমন পদ্ধতির ছোঁড়া অনুচ্ছেদে চেক করা ব্যতিক্রম যুক্ত (বা যুক্ত করতে ভুলবেন না) তবে চেকড ব্যতিক্রম ছোঁড়ার এই 2 পরিণতি সম্পর্কে সচেতন হন:

1) কলিং-কোড নামটি এটি ধরতে সক্ষম হবে না (যদি আপনি চেষ্টা করেন, সংকলকটি বলবে: ব্যতিক্রমটি সংশ্লিষ্ট চেষ্টা বিবৃতিতে কোনও দিনই ছোঁড়া হয় না)। এটি বুদবুদ হবে এবং সম্ভবত কিছু "ক্যাচ এক্সেপশন" বা "ক্যাচ থ্রোয়েবল" দ্বারা মূল প্রোগ্রামের লুপে ধরা হবে, যা আপনি যাইহোক চান তা হতে পারে।

2) এটি সর্বনিম্ন আশ্চর্যের নীতি লঙ্ঘন করে: সমস্ত সম্ভাব্য ব্যতিক্রম ধরা গ্যারান্টি দিতে সক্ষম হওয়ার জন্য রানটাইম এক্সেকশনকে ধরে নেওয়া এখন আর যথেষ্ট হবে না। এই কারণে, আমি বিশ্বাস করি এটি ফ্রেমওয়ার্ক কোডে করা উচিত নয়, তবে কেবলমাত্র এমন ব্যবসায়িক কোডে যা আপনি সম্পূর্ণরূপে নিয়ন্ত্রণ করেন।

উপসংহারে: আমি বিশ্বাস করি যে এখানে সীমাবদ্ধতাগুলি গুরুতর নয় এবং UtilExceptionক্লাসটি নির্ভয়ে ব্যবহার করা যেতে পারে। তবে এটি আপনার উপর!


8

Streamএকটি চেক না করা ব্যতিক্রম ছুঁড়তে এবং তারপরে টার্মিনাল ক্রিয়াকলাপগুলিতে সেই চিরচেনা ব্যতিক্রমটি মোড়ক থেকে ঝুলিয়ে আপনার ল্যাম্বদাটি মোড়ানোর মাধ্যমে আপনি নিজের নিজস্ব বৈকল্পিকটি সম্ভাব্যভাবে রোল করতে পারেন :

@FunctionalInterface
public interface ThrowingPredicate<T, X extends Throwable> {
    public boolean test(T t) throws X;
}

@FunctionalInterface
public interface ThrowingFunction<T, R, X extends Throwable> {
    public R apply(T t) throws X;
}

@FunctionalInterface
public interface ThrowingSupplier<R, X extends Throwable> {
    public R get() throws X;
}

public interface ThrowingStream<T, X extends Throwable> {
    public ThrowingStream<T, X> filter(
            ThrowingPredicate<? super T, ? extends X> predicate);

    public <R> ThrowingStream<T, R> map(
            ThrowingFunction<? super T, ? extends R, ? extends X> mapper);

    public <A, R> R collect(Collector<? super T, A, R> collector) throws X;

    // etc
}

class StreamAdapter<T, X extends Throwable> implements ThrowingStream<T, X> {
    private static class AdapterException extends RuntimeException {
        public AdapterException(Throwable cause) {
            super(cause);
        }
    }

    private final Stream<T> delegate;
    private final Class<X> x;

    StreamAdapter(Stream<T> delegate, Class<X> x) {
        this.delegate = delegate;
        this.x = x;
    }

    private <R> R maskException(ThrowingSupplier<R, X> method) {
        try {
            return method.get();
        } catch (Throwable t) {
            if (x.isInstance(t)) {
                throw new AdapterException(t);
            } else {
                throw t;
            }
        }
    }

    @Override
    public ThrowingStream<T, X> filter(ThrowingPredicate<T, X> predicate) {
        return new StreamAdapter<>(
                delegate.filter(t -> maskException(() -> predicate.test(t))), x);
    }

    @Override
    public <R> ThrowingStream<R, X> map(ThrowingFunction<T, R, X> mapper) {
        return new StreamAdapter<>(
                delegate.map(t -> maskException(() -> mapper.apply(t))), x);
    }

    private <R> R unmaskException(Supplier<R> method) throws X {
        try {
            return method.get();
        } catch (AdapterException e) {
            throw x.cast(e.getCause());
        }
    }

    @Override
    public <A, R> R collect(Collector<T, A, R> collector) throws X {
        return unmaskException(() -> delegate.collect(collector));
    }
}

তারপরে আপনি এটিকে ঠিক একইভাবে ব্যবহার করতে পারেন Stream:

Stream<Account> s = accounts.values().stream();
ThrowingStream<Account, IOException> ts = new StreamAdapter<>(s, IOException.class);
return ts.filter(Account::isActive).map(Account::getNumber).collect(toSet());

এই সমাধানটির জন্য বেশ কিছুটা বয়লারপ্লেটের প্রয়োজন হবে, তাই আমি আপনাকে পরামর্শ দিয়েছি যে আমি ইতিমধ্যে তৈরি করা লাইব্রেরিটি একবার দেখে নিন যা পুরো Streamশ্রেণীর (এবং আরও অনেক কিছু) এখানে আমি বর্ণনা করেছি ঠিক তেমন করে ।


হ্যালো ... ছোট বাগ? new StreamBridge<>(ts, IOException.class);->new StreamBridge<>(s, IOException.class);
কেভিনার্পে

1
@ কেভিনার্পে ইয়েপ এটাও বলা উচিত ছিল StreamAdapter
জেফ্রি

5

#Propagate () পদ্ধতি ব্যবহার করুন। থেকে নমুনা অ পেয়ারা বাস্তবায়ন স্যাম Beran দ্বারা জাভা 8 ব্লগ :

public class Throwables {
    public interface ExceptionWrapper<E> {
        E wrap(Exception e);
    }

    public static <T> T propagate(Callable<T> callable) throws RuntimeException {
        return propagate(callable, RuntimeException::new);
    }

    public static <T, E extends Throwable> T propagate(Callable<T> callable, ExceptionWrapper<E> wrapper) throws E {
        try {
            return callable.call();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw wrapper.wrap(e);
        }
    }
}

জাভা 8 ব্লগের লিঙ্কটি মারা গেছে।
স্পাইচো

4

এটি সরাসরি প্রশ্নের উত্তর দেয় না (এমন আরও অনেক উত্তর রয়েছে যা করে) তবে সমস্যাটি প্রথম দিকে এড়াতে চেষ্টা করে:

আমার অভিজ্ঞতায় একটি Stream(বা অন্যান্য ল্যাম্বডা এক্সপ্রেশন) ব্যতিক্রমগুলি পরিচালনা করার প্রয়োজনীয়তাটি প্রায়শই এই সত্য থেকে আসে যে ব্যতিক্রমগুলি যেখানে নিক্ষেপ করা উচিত নয় সেগুলি থেকে ফেলে দেওয়া হবে বলে ঘোষণা করা হয়। এটি প্রায়শই ইন-এবং আউটপুটটির সাথে ব্যবসায়িক যুক্তিকে মেশানো থেকে আসে। আপনার Accountইন্টারফেস একটি নিখুঁত উদাহরণ:

interface Account {
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
}

IOExceptionপ্রতিটি গেটারের উপরে একটি নিক্ষেপ করার পরিবর্তে , এই নকশাটি বিবেচনা করুন:

interface AccountReader {
    Account readAccount(…) throws IOException;
}

interface Account {
    boolean isActive();
    String getNumber();
}

পদ্ধতিটি AccountReader.readAccount(…)একটি ডাটাবেস বা একটি ফাইল বা যা কিছু থেকে একটি অ্যাকাউন্ট পড়তে পারে এবং যদি এটি সফল না হয় তবে একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারে। এটি Accountএমন একটি অবজেক্ট তৈরি করে যা ইতিমধ্যে সমস্ত মান রয়েছে, যা ব্যবহারের জন্য প্রস্তুত। যেহেতু মানগুলি ইতিমধ্যে লোড হয়ে গেছে readAccount(…), গ্রাহকরা একটি ব্যতিক্রম ছুঁড়বেন না। সুতরাং আপনি ব্যতিক্রম মোড়ানো, মাস্কিং বা গোপনের প্রয়োজন ছাড়াই ল্যাম্বডাসে এগুলি অবাধে ব্যবহার করতে পারেন।

অবশ্যই আমি যেভাবে বর্ণনা করেছি এটি করা সর্বদা সম্ভব নয়, তবে প্রায়শই এটি হয় এবং এটি পুরোপুরি ক্লিনার কোডের দিকে নিয়ে যায় (আইএমএইচও):

  • উদ্বেগের আরও ভাল বিচ্ছেদ এবং একক দায়িত্বের নীতি অনুসরণ করা
  • কম বয়লারপ্লেট: আপনাকে throws IOExceptionকোনও কোড ব্যবহার করে সংকলককে সন্তুষ্ট করার সাথে আপনার কোডটি বিশৃঙ্খলা করতে হবে না
  • ত্রুটি হ্যান্ডলিং: আপনি যখন ত্রুটিগুলি ঘটে সেগুলি হ্যান্ডেল করেন - কোনও ফাইল বা ডাটাবেস থেকে পড়ার সময় - আপনার ব্যবসায়িক যুক্তির মাঝখানে কোথাও পরিবর্তে কেবল কারণ আপনি ক্ষেত্রের মান পেতে চান
  • আপনি এর সুবিধাগুলি থেকে Account অপরিবর্তনীয় এবং লাভ করতে সক্ষম হতে পারেন (যেমন থ্রেড সুরক্ষা)
  • Accountল্যাম্বডাসে ব্যবহার করার জন্য আপনার "নোংরা কৌশল" বা ওয়ার্কআউন্ডের প্রয়োজন হবে না (উদাহরণস্বরূপ এ Stream)

4

এটা দিয়ে সহজ কোড নিচে দ্বারা সমাধান করা যেতে পারে স্ট্রিম এবং চেষ্টা মধ্যে AbacusUtil :

Stream.of(accounts).filter(a -> Try.call(a::isActive)).map(a -> Try.call(a::getNumber)).toSet();

প্রকাশ : আমি এর বিকাশকারী AbacusUtil


3

@ মার্কস সমাধানটি প্রসারিত করে আপনি সাধারণত স্ট্রিমগুলিতে একটি চেক করা ব্যতিক্রম ছোঁড়া এবং ধরতে পারেন ; অর্থাত , সংকলক আপনাকে বাহিরের বাইরে যেমন ছিল তেমন ধরতে / পুনরায় নিক্ষেপ করতে বলবে !!

@FunctionalInterface
public interface Predicate_WithExceptions<T, E extends Exception> {
    boolean test(T t) throws E;
}

/**
 * .filter(rethrowPredicate(t -> t.isActive()))
 */
public static <T, E extends Exception> Predicate<T> rethrowPredicate(Predicate_WithExceptions<T, E> predicate) throws E {
    return t -> {
        try {
            return predicate.test(t);
        } catch (Exception exception) {
            return throwActualException(exception);
        }
    };
}

@SuppressWarnings("unchecked")
private static <T, E extends Exception> T throwActualException(Exception exception) throws E {
    throw (E) exception;
}

তারপরে, আপনার উদাহরণটি নিম্নরূপ লিখিত হবে (এটি আরও পরিষ্কারভাবে দেখানোর জন্য পরীক্ষাগুলি যোগ করা):

@Test
public void testPredicate() throws MyTestException {
    List<String> nonEmptyStrings = Stream.of("ciao", "")
            .filter(rethrowPredicate(s -> notEmpty(s)))
            .collect(toList());
    assertEquals(1, nonEmptyStrings.size());
    assertEquals("ciao", nonEmptyStrings.get(0));
}

private class MyTestException extends Exception { }

private boolean notEmpty(String value) throws MyTestException {
    if(value==null) {
        throw new MyTestException();
    }
    return !value.isEmpty();
}

@Test
public void testPredicateRaisingException() throws MyTestException {
    try {
        Stream.of("ciao", null)
                .filter(rethrowPredicate(s -> notEmpty(s)))
                .collect(toList());
        fail();
    } catch (MyTestException e) {
        //OK
    }
}

এই উদাহরণটি সংকলন করে না
রোমান এম

হাই @ রোমানম এটি দেখানোর জন্য ধন্যবাদ: আমি "থ্রোআ্যাক্টুয়াল এক্সেপশন" পদ্ধতিতে অনুপস্থিত রিটার্নের ধরণটি সংশোধন করেছি। আমরা এটি উত্পাদনে ব্যবহার করছি তাই আমি আশা করি এটিও আপনার পক্ষে কাজ করছে।
পাওলোক

3

আইওএক্সেপশন (রানটাইম এক্সেপশন-এ) হ্যান্ডলিং কোডটি সঠিকভাবে যুক্ত করতে, আপনার পদ্ধতিটি দেখতে এরকম হবে:

Stream<Account> s =  accounts.values().stream();

s = s.filter(a -> { try { return a.isActive(); } 
  catch (IOException e) { throw new RuntimeException(e); }});

Stream<String> ss = s.map(a -> { try { return a.getNumber() }
  catch (IOException e) { throw new RuntimeException(e); }});

return ss.collect(Collectors.toSet());

এখন সমস্যাটি হ'ল IOExceptionইচ্ছাটিকে একটি হিসাবে ক্যাপচার করতে হবে RuntimeExceptionএবং একটিতে রূপান্তর IOExceptionকরতে হবে - এবং এটি উপরের পদ্ধতিতে আরও বেশি কোড যুক্ত করবে।

Streamযখন এটি ঠিক এভাবে করা যায় তখন কেন ব্যবহার করবেন - এবং পদ্ধতিটি ছুঁড়ে দেয় IOExceptionযাতে তার জন্যও কোনও অতিরিক্ত কোডের প্রয়োজন হয় না:

Set<String> set = new HashSet<>();
for(Account a: accounts.values()){
  if(a.isActive()){
     set.add(a.getNumber());
  } 
}
return set;

1

এই সমস্যাটি মাথায় রেখে আমি পরীক্ষিত ব্যতিক্রম এবং ল্যাম্বডাসকে মোকাবেলার জন্য একটি ছোট গ্রন্থাগার তৈরি করেছি। কাস্টম অ্যাডাপ্টারগুলি আপনাকে বিদ্যমান কার্যকরী ধরণের সাথে সংহত করতে দেয়:

stream().map(unchecked(URI::new)) //with a static import

https://github.com/TouK/ThrowingFunction/


1

আপনার উদাহরণ হিসাবে লেখা যেতে পারে:

import utils.stream.Unthrow;

class Bank{
   ....
   public Set<String> getActiveAccountNumbers() {
       return accounts.values().stream()
           .filter(a -> Unthrow.wrap(() -> a.isActive()))
           .map(a -> Unthrow.wrap(() -> a.getNumber()))
           .collect(Collectors.toSet());
   }
   ....
}

Unthrow বর্গ এখানে গ্রহণ করা যেতে পারে https://github.com/SeregaLBN/StreamUnthrower


0

যদি আপনি তৃতীয় পক্ষের গ্রন্থাগারগুলি ব্যবহার করতে আপত্তি করেন না, তবে এওএলির সাইক্লোপস-রিঅ্যাক্ট লাইব, প্রকাশ :: আমি একজন সহযোগী, একটি এক্সপশনসফ্টনার ক্লাস রয়েছে যা এখানে সহায়তা করতে পারে।

 s.filter(softenPredicate(a->a.isActive()));

0

জাভার ক্রিয়ামূলক ইন্টারফেসগুলি কোনও পরীক্ষিত বা চেক করা ব্যতিক্রম ঘোষণা করে না। আমাদের থেকে পদ্ধতিগুলির স্বাক্ষরটি পরিবর্তন করতে হবে:

boolean isActive() throws IOException; 
String getNumber() throwsIOException;

প্রতি:

boolean isActive();
String getNumber();

অথবা ট্রাই-ক্যাচ ব্লক দিয়ে এটি পরিচালনা করুন:

public Set<String> getActiveAccountNumbers() {
  Stream<Account> s =  accounts.values().stream();
  s = s.filter(a -> 
    try{
      a.isActive();
    }catch(IOException e){
      throw new RuntimeException(e);
    }
  );
  Stream<String> ss = s.map(a -> 
    try{
      a.getNumber();
    }catch(IOException e){
      throw new RuntimeException(e);
    }
  );
  return ss.collect(Collectors.toSet());
}

আর একটি বিকল্প হ'ল একটি কাস্টম মোড়ক লিখুন বা থ্রোওং ফাংশনের মতো একটি লাইব্রেরি ব্যবহার করুন। লাইব্রেরির সাথে আমাদের কেবলমাত্র আমাদের pom.xML এ নির্ভরতা যুক্ত করতে হবে:

<dependency>
    <groupId>pl.touk</groupId>
    <artifactId>throwing-function</artifactId>
    <version>1.3</version>
</dependency>

এবং থ্রোয়িং ফাংশন, থ্রোয়িংকনসুমার, থ্রোয়িং প্রিডিকেট, থ্রোংআরনেবল, থ্রোংস্পপ্লায়ারের মতো নির্দিষ্ট ক্লাসগুলি ব্যবহার করুন।

শেষে কোডটি এর মতো দেখাচ্ছে:

public Set<String> getActiveAccountNumbers() {
  return accounts.values().stream()
    .filter(ThrowingPredicate.unchecked(Account::isActive))
    .map(ThrowingFunction.unchecked(Account::getNumber))
    .collect(Collectors.toSet());
}

0

আমি প্রবাহে চেক করা ব্যতিক্রম (জাভা -8) হ্যান্ডল করার কোনও উপায় দেখতে পাচ্ছি না, কেবলমাত্র আমি প্রয়োগ করেছিলাম প্রবাহে চেক করা ব্যতিক্রম এবং তাদের চেক করা ব্যতিক্রম হিসাবে পুনরায় নিক্ষেপ করা।

        Arrays.stream(VERSIONS)
        .map(version -> TemplateStore.class
                .getClassLoader().getResourceAsStream(String.format(TEMPLATE_FILE_MASK, version)))
        .map(inputStream -> {
            try {
                return ((EdiTemplates) JAXBContext.newInstance(EdiTemplates.class).createUnmarshaller()
                        .unmarshal(inputStream)).getMessageTemplate();
            } catch (JAXBException e) {
                throw new IllegalArgumentException(ERROR, e);
            }})
        .flatMap(Collection::stream)
        .collect(Collectors.toList());

আপনি কি আসলে প্রশ্নের উত্তর দেওয়ার চেষ্টা করছেন?
নীলাম্বর শর্মা

@ নীলাম্বর - আমি এখানে যা বলতে চাইছি তা হ'ল, জাভা প্রবাহটি ব্যবহার করার সময় চেক করা ব্যতিক্রমগুলি পরিচালনা করার কোনও উপায় নেই ... সবকিছুর শেষে আমাদের চেকডকে ধরতে হবে এবং রান-টাইম / চেক করা ছাড়াই ফেলতে হবে .. এখন দুটি জিনিস রয়েছে, ১. আপনি যদি আমার বোধগম্যতার সাথে সঠিক না হন তবে দয়া করে আমাকে সংশোধন করুন বা ২. যদি আপনি মনে করেন, আমার পোস্টটি অপ্রাসঙ্গিক, আমি এটি মুছে ফেলতে পেরে খুশি। শুভেচ্ছা, অতুল
অতুল সচান

0

আপনি যদি স্ট্রিমের মধ্যে ব্যতিক্রমগুলি পরিচালনা করতে চান এবং অতিরিক্তগুলি প্রক্রিয়া চালিয়ে যেতে চান তবে ব্রাইড ভার্মির একটি জনের ধারণাটি ব্যবহার করে ডিজেনে একটি দুর্দান্ত নিবন্ধ আছে । এটি এই পরিস্থিতি পরিচালনা করার একটি দুর্দান্ত উপায় দেখায়। নিখোঁজ একমাত্র জিনিস নমুনা কোড। এটি নিবন্ধের ধারণাগুলি ব্যবহার করে আমার অন্বেষণের একটি নমুনা।

@Test
public void whenValuePrinted_thenPrintValue() {

    List<Integer> intStream = Arrays.asList(0, 1, 2, 3, 4, 5, 6);
    intStream.stream().map(Either.liftWithValue(item -> doSomething(item)))
             .map(item -> item.isLeft() ? item.getLeft() : item.getRight())
             .flatMap(o -> {
                 System.out.println(o);
                 return o.isPresent() ? Stream.of(o.get()) : Stream.empty();
             })
             .forEach(System.out::println);
}

private Object doSomething(Integer item) throws Exception {

    if (item == 0) {
        throw new Exception("Zero ain't a number!");
    } else if (item == 4) {
        return Optional.empty();
    }

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