Приведите содержание необязательно или потоков - PullRequest
0 голосов
/ 31 октября 2018

Я хотел бы вместо того, чтобы писать свой собственный метод или класс, я мог бы просто проверить и привести содержимое необязательного к другому классу или иметь пустой объект.

Для этой подзадачи в приложении я хочу, чтобы пользовательский объект пользователя экземпляра TreeNode был приведен к CustomUserObject, при условии, что TreeNode является экземпляром DefaultMutableTreeNode.

private Optional<CustomUserObject> getCustomUserObject(TreeNode node) {
    Optional<DefaultMutableTreeNode> optDefaultMutableTreeNode = OptionalUtil.cast(Optional.ofNullable(node), DefaultMutableTreeNode.class);
    Optional<Object> optUserObject = optDefaultMutableTreeNode.map(DefaultMutableTreeNode::getUserObject); //
    return OptionalUtil.cast(optUserObject, CustomUserObject.class);
}


/**
 * Maps the given optional, if the containing element is an instance of the given class.
 * Returns empty if the containing object is not an instance of the given class.
 * 
 * @param orgOptional
 *        given optional
 * @param clazz
 *        given class.
 * @return the resulting {@link Optional}.
 */
public static <T, X> Optional<T> cast(Optional<X> orgOptional, Class<T> clazz) {
    return orgOptional //
        .filter(clazz::isInstance) // check instance
        .map(clazz::cast); // cast
}

/**
 * Maps the given stream, if the containing element is an instance of the given class.
 * Returns empty if the containing object is not an instance of the given class.
 * 
 * @param orgStream
 *        given optional
 * @param clazz
 *        given class.
 * @return the resulting {@link Optional}.
 */
public static <T, X> Stream<T> cast(Stream<X> orgStream, Class<T> clazz) {
    return orgStream //
        .filter(clazz::isInstance) // check instance
        .map(clazz::cast); // cast
}

Я помню, что мне нужно часто разыгрывать опционные или потоковые трансляции. Это не свободно. На самом деле, я бы хотел, чтобы java для Optional или Stream имел метод приведения, который выполняет вышеуказанный шаг. Я не хочу писать свой собственный свободный CustomOptional. Я что-то пропустил? Есть ли способ сделать это более простым способом?

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

Я придумал это для Дополнительно

/**
 * Creates a function that tries to cast to the given class.
 * If the given argument is not an instance of the given class <code>Optional.empty()</code> is returned.
 * This function can be used in an <code>optionalObject.flatMap(Functional.cast(SomeClass.class))</code> context.
 * 
 * @author xne9645
 * @param clazz
 *        given Clazz
 * @return Returns an optional of the given class.
 * @param <X>
 *        generic input argument for the function
 * @param <T>
 *        type of the output of the function
 */
public static <X, T> Function<X, Optional<T>> cast(Class<? extends T> clazz) {
    return x -> {
        if (clazz.isInstance(x)) {
            return Optional.of(clazz.cast(x));
        }
        return Optional.empty();
    };
}

и используйте его так:

Optional<DefaultMutableTreeNode> optParent = Optional.of(node) // optional of original node
                    .map(ProfileTreeNode::getParent) // parent of this node.
                    .flatMap(FunctionalUtil.cast(DefaultMutableTreeNode.class)); // cast to DefaultMutableTreeNode
                optParent.ifPresent(y -> y.remove(node));

Для потоков Я написал

/**
 * Creates a function that tries to cast to the given class.
 * If the given argument is not an instance of the given class an empty stream is returned.
 * This function can be used in an <code>stream.flatMap(Functional.castStream(SomeClass.class))</code> context.
 * 
 * @author xne9645
 * @param clazz
 *        given Clazz
 * @return Returns an optional of the given class.
 * @param <X>
 *        generic input argument for the function
 * @param <T>
 *        type of the output of the function
 */
public static <X, T> Function<X, Stream<T>> castStream(Class<? extends T> clazz) {
    return x -> Stream.of(x) // stream of x.
        .filter(clazz::isInstance) // check if instance
        .map(clazz::cast);
}
0 голосов
/ 01 ноября 2018

Вы можете легко сделать это более свободно, полагаясь на методы map() / flatMap() и cast, которые вместо этого возвращают функции.

Для Optional это очень просто, поскольку map() может выступать в качестве фильтра, возвращая null. Так что просто определите:

public static <U> Function<Object, U> filterAndCast(Class<? extends U> clazz) {
    return t -> clazz.isInstance(t) ? clazz.cast(t) : null;
}

и используйте его как:

Optional<Number> number = Optional.of(42L);
System.out.println(number.map(filterAndCast(Integer.class)));
System.out.println(number.map(filterAndCast(Long.class)));

Выход:

Optional.empty
Optional[42]

Для потоков вы можете применить более или менее тот же трюк, полагаясь на flatMap() с функцией, которая возвращает пустое Stream:

public static <U> Function<Object, Stream<U>> streamFilterAndCast(Class<? extends U> clazz) {
    return t -> clazz.isInstance(t) ? Stream.of(clazz.cast(t)) : Stream.empty();
    // or alternatively
    return t -> Stream.of(t).filter(clazz::isInstance).map(clazz::cast);
}

и используйте его как:

Stream.of(42L, "Hello world", 1024, 3.14)
        .flatMap(streamFilterAndCast(Number.class))
        .forEach(System.out::println);

Выход:

42
1024
3.14
...