java 8 switch case default with break for class ty

2019-06-05 23:40发布

I was looking for switch over type for java, and I found a solution here: Switch over type in java

But the issue, solution was not really like a switch with breaks, sure this will happen because I loop over Consumers , I want to know a good way to modify my current code or clean alternative to have something to handle my class type, and break after handle first match and the default is to handle the unmatched only ( here it is the parent class StripeObject) .

My business is to handle stripe events from webhooks, I'm using stripe-java, so my code now something like this:

    public void handleWebHookEvent(Event eventJson) throws CardException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException {
        Stripe.apiKey = configuration.getString(AppConstants.STRIPE_API_KEY);

        // Verify the event by fetching it from Stripe
        Event event = Event.retrieve(eventJson.getId());
        Logger.debug(AppUtils.concatStrings("|-> Event Received: [", event.getId(), "] Type: [", event.getType(), "] Request ID: [", event.getRequest(), "]"));
        handleEventObject(event.getData().getObject());
    }

    private void handleEventObject(StripeObject stripeObject) {
        switchType(stripeObject,
                caze(Customer.class, this::handleEventObject),
                caze(Card.class, this::handleEventObject),
                caze(Charge.class, this::handleEventObject),
                caze(Transfer.class, this::handleEventObject)
                caze(StripeObject.class, object -> Logger.debug(AppUtils.concatStrings("|--> !!! Not Handled StripeObject !!! [", object.toString(), "]")))
        );
    }

    private void handleEventObject(Customer customer) {
        Logger.debug(AppUtils.concatStrings("|--> Customer ID <Description> : [", customer.getId(), " <", customer.getDescription(), ">]"));
    }

    private void handleEventObject(Card card) {
        Logger.debug(AppUtils.concatStrings("|--> Card ID <Brand> : [", card.getId(), " <", card.getBrand(), ">]"));
    }

    private void handleEventObject(Charge charge) {
        Logger.debug(AppUtils.concatStrings("|--> Charge ID <Description , Customer , Amount> : [", charge.getId(), " <", charge.getDescription(), " , ", charge.getCustomer() ," , ", charge.getAmount(), ">]"));
    }

    private void handleEventObject(Transfer transfer) {
        Logger.debug(AppUtils.concatStrings("|--> Transfer ID <Description , Destination , Amount> : [", transfer.getId(), " <", transfer.getDescription(), " , ", transfer.getDestination() ," , ", transfer.getAmount(), ">]"));
    }

    @SuppressWarnings("unchecked")
    private static <T> void switchType(StripeObject stripeObject, Consumer... consumers) {
        for (Consumer consumer : consumers)
            consumer.accept(stripeObject);
    }

    private static <T> Consumer caze(Class<T> clazz, Consumer<T> consumer) {
        return obj -> Optional.of(obj).filter(clazz::isInstance).map(clazz::cast).ifPresent(consumer);
    }

In the current code, if the evnet was Customer as example it will print :

|--> Customer ID <Description> ... etc

Then

|--> !!! Not Handled StripeObject !!! ... etc

It must print only the first line, not the second if match.

1条回答
啃猪蹄的小仙女
2楼-- · 2019-06-06 00:39

You only have to change the methods switchType and caze to use a Predicate instead of a Consumer, so the loop can stop at the first match. The rest of the code doesn’t need any change:

@SafeVarargs
private static void switchType(StripeObject so, Predicate<Object>... predicates) {
    for(Predicate<Object> predicate : predicates)
        if(predicate.test(so)) return;
}

private static <T> Predicate<Object> caze(Class<T> clazz, Consumer<T> consumer) {
    return obj -> {
        if(clazz.isInstance(obj)) {
            consumer.accept(clazz.cast(obj));
            return true;
        }
        return false;
    };
}

Note that this still differs from the switch semantics, as a switch statement precludes ambiguous cases in general. Here, one of the types still could be a subtype of another, so, unlike a switch statement, the order of case statements does matter then.

If all cases are distinct, this is not an issue.

查看更多
登录 后发表回答