В целях отладки я пытаюсь создать строковые представления лямбда-выражений (в частности, 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() не переопределяется).
Я не уверен, возможно ли что-то подобное, например. с отражением, я, конечно, пока ничего не смог найти на нем. Любые идеи?
Ответ 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]}, что, я думаю, не обязательно яснее, чем если бы вы вручную дали им описание, но, возможно, полезно для предикатов, которые не находятся под вашим контролем.