Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Создание строкового представления лямбда-выражения

Автор вопроса: blalasaadriОтветов: 1

В целях отладки я пытаюсь создать строковые представления лямбда-выражений (в частности, Predicates, хотя это было бы интересно и для других лямбда-выражений) в Java 8. Моя идея будет примерно такой:

public class Whatever {

    private static <T> String predicateToString(Predicate<T> predicate) {
        String representation = ... // do magic
        return representation;
    }

    public static void main(String[] args) {
        System.out.println(Whatever.<Integer>predicateToString(i -> i % 2 == 0));
    }

}

И вывод будет i -> i % 2 == 0 (или что-то логически эквивалентное). Метод toString(), похоже, бесполезен, на выходе получается что-то вроде com.something.Whatever$$Lambda$1/1919892312@5e91993f (чего, я думаю, следует ожидать, поскольку toString() не переопределяется).

Я не уверен, возможно ли что-то подобное, например. с отражением, я, конечно, пока ничего не смог найти на нем. Любые идеи?

  • Отладочные цели? Вы не можете просто посмотреть на источник? Sotirios Delimanolis 17.05.2014
  • Для этого потребуется декомпилятор. SLaks 17.05.2014
  • @SotiriosDelimanolis Конечно, я всегда могу посмотреть на источник. Но было бы неплохо иметь и печатное представление. blalasaadri 17.05.2014
  • Тогда нельзя просто скопировать исходник? Jeroen Vannevel 17.05.2014
  • @JeroenVannevel Вы имеете в виду просто каждый раз писать строковое представление вручную? Возможно, конечно. Но не очень элегантно. blalasaadri 17.05.2014
  • У вас могут быть макросы в Java (#define). Это нехорошо, но вы можете определить предикат, который в то же время также создает строку того же содержания. Я бы не стал этого делать. Trilarion 17.05.2014

javajava-8lambdatostringpredicates

Ответы

Ответ 1 · рейтинг 20 · andersschuller

Самое простое, что я мог придумать, это создать "именованный предикат", который дает вашим предикатам имя или описание, в основном все, что будет полезно в качестве toString:

public class NamedPredicate<T> implements Predicate<T> {
    private final String name;
    private final Predicate<T> predicate;

    public NamedPredicate(String name, Predicate<T> predicate) {
        this.name = name;
        this.predicate = predicate;
    }

    @Override
    public boolean test(T t) {
        return predicate.test(t);
    }

    @Override
    public String toString() {
        return name;
    }

    public static void main(String... args) {
        Predicate<Integer> isEven = new NamedPredicate<>("isEven", i -> i % 2 == 0);
        System.out.println(isEven); // prints isEven
    }
}

Возможно, предоставление вашим предикатам имен или описаний, подобных этому, также делает код, в котором вы их используете, более понятным:

Stream.of(1, 2, 3, 4)
        .filter(isEven)
        .forEach(System.out::println);

Более странная идея может состоять в том, чтобы получить "структурное" описание предиката, т. е. каков результат для некоторых заданных входных данных? Очевидно, что это будет работать лучше всего, когда входной набор конечен и мал (например, для перечислений, логических значений или какого-либо другого ограниченного набора), но я думаю, вы могли бы попробовать небольшой набор "случайных" целых чисел для целочисленных предикатов:

private static Map<Boolean, List<Integer>> testPredicate(Predicate<Integer> predicate) {
    return Stream.of(-35, -3, 2, 5, 17, 29, 30, 460)
            .collect(Collectors.partitioningBy(predicate));
}

Для isEven это вернет что-то вроде {false=[-35, -3, 5, 17, 29], true=[2, 30, 460]}, что, я думаю, не обязательно яснее, чем если бы вы вручную дали им описание, но, возможно, полезно для предикатов, которые не находятся под вашим контролем.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы