Как передать функцию в функцию java
Передать функцию в качестве параметра в другую функцию можно разными способами. Рассмотрим некоторые из них.
1) Воспользуемся функциональным интерфейсом Predicate :
import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; public class App public static void main(String[] args) ListString> list1 = List.of("1", "22", "333", "4444"); ListString> filteredList1 = filterList(list1, x -> x.length() >= 3); System.out.println(filteredList1); // => [333, 4444] ListInteger> list2 = List.of(1, 2, 3, 4); ListInteger> filteredList2 = filterList(list2, x -> x >= 3); System.out.println(filteredList2); // => [3, 4] > public static T> ListT> filterList(ListT> list, PredicateT> rool) return list.stream() .filter(x -> rool.test(x)) .collect(Collectors.toList()); > >
2) Воспользуемся готовым функциональным интерфейсом UnaryOperator :
public static void superMethod(UnaryOperatorString> method) String str = "Hexlet"; String result = method.apply(str); System.out.println(result); > // вызов с передачей методов public class App public static void main(String[] args) throws Exception // передадим стандартный метод superMethod(String::toUpperCase); // => HEXLET // передадим лямбда-функцию superMethod(s -> s + "!"); // => hexlet! // передадим собственный метод superMethod(App::reverse); // => telxeh > public static String reverse(String str) StringBuilder builder = new StringBuilder(); builder.append(str); return builder.reverse().toString(); > >
3) Создадим собственный интерфейс и передадим объект этого типа в нашу функцию :
interface MyInterface int count(int a, int b, int c); > public static void superMethodInterface(MyInterface method) int a = 5, b = 10, c = 20; int result = method.count(a, b, c); System.out.println(result); > // вызов с передачей методов public class App public static void main(String[] args) throws Exception MyInterface count = new MyInterface() @Override public int count(int a, int b, int c) return a + b + c; > >; superMethodInterface(count); // => 35 superMethodInterface((a,b,c) -> a * b * c); // => 1000 superMethodInterface((a,b,c) -> a + b - c); // => -5 > >
4) Получим метод с помощью рефлексии и передадим его :
public static void superMethodReflection(Object object, Method method) throws Exception int a = 10; int b = 20; int result = (int) method.invoke(object, a, b); System.out.println(result); > // вызов с передачей методов public class App public static void main(String[] args) throws Exception // передадим стандартный метод Method method = Integer.class.getDeclaredMethod("max", int.class, int.class); superMethodReflection(0, method); // => 20 method = Integer.class.getDeclaredMethod("sum", int.class, int.class); superMethodReflection(0, method); // => 30 // передадим собственный метод method = App.class.getDeclaredMethod("concate", int.class, int.class); superMethodReflection(new App(), method); // => 1020 > public static int concate(int a, int b) return Integer.parseInt("" + a + b); > >
Помогите разобраться с StackTraceElement[]
Доброго времени суток. Помогите понять суть StackTrace.
В учебном материале даётся объяснение
Java-машина ведет запись всех вызовов функций. У нее есть для этого специальная коллекция – стек. Когда одна функция вызывает другую, Java-машина помещает в этот стек новый элемент StackTraceElement. Когда функция завершается этот элемент удаляется из стека. Таким образом, в этом стеке всегда хранится актуальная информация о текущем состоянии «стека вызовов функций»
public static void main(String[] args) < method1(); >public static void method1() < method2(); >public static void method2() < method3(); >public static void method3() < StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); for (StackTraceElement element : stackTraceElements) < System.out.println(element.getMethodName()); >>
В результате выполнения которого мы получаем
getStackTrace method3 method2 method1 main
Если я правильно все понимаю, то конструкция
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
работает следующим образом:
//Cоздаём переменную типа StackTraceElement[] StackTraceElement[] stackTraceElements //Присваеваем ей ссылку на текущий поток и заносим в массив специальные элементы StackTrace Thread.currentThread().getStackTrace()
Вопрос №1: каким образом в этом массиве StackTraceElement[] вся информация о вызываемых методах, если сказано, что после выполнения метода информация из стека удаляется?
Вопрос №2: В одном из заданий просят вернуть имя метода, который его вызывает
public static void main(String[] args) throws Exception < method1(); >public static String method1() < method2(); return Thread.currentThread().getStackTrace()[2].getMethodName(); >public static String method2() < method3(); return Thread.currentThread().getStackTrace()[2].getMethodName(); >public static String method3() < method4(); return Thread.currentThread().getStackTrace()[2].getMethodName(); >public static String method4() < method5(); return Thread.currentThread().getStackTrace()[2].getMethodName(); >public static String method5()
Каким образом работает конструкция
return Thread.currentThread().getStackTrace()[2].getMethodName();
если мы не создавали StackTraceElement[] . Значит ли это, что он неявно создается JVM при выполнении программы?
Ответы (3 шт):
Вопрос №1: каким образом в этом массиве StackTraceElement[] вся информация о вызываемых методах, если сказано, что после выполнения метода информация из стека удаляется?
Вы вызываете метод getStackTrace() в методе method3() . На момент вызова getStackTrace() метод method3() еще не завершился, следовательно, метод getStackTrace() возвратит всю цепочку вызовов вплоть до вызова метода getStackTrace() .
Если, например, Вы вызовете getStackTrace() в методе main(. ) после вызова метода method1() , то получите следующий вывод:
Вы не видите тут методов method1() и прочих – записи об их вызовах были удалены, так как на момент вызова метода getStackTrace() метод method1() был завершен.
Вопрос №2: В одном из заданий просят вернуть имя метода, который его вызывает
.
Каким образом работает конструкция
return Thread.currentThread().getStackTrace()[2].getMethodName();
если мы не создавали StackTraceElement[]. Значит ли это, что он неявно создается JVM при выполнении программы?
Да, значит. Элементы в стек вызовов добавляет сама JVM.
На вершине стека находится запись о вызове самого метода getStackTrace() , за ним следует запись об имени метода, непосредственно в котором был вызван метод getStackTrace() , в элементе getStackTrace()[i] ( i>0 ) находится имя метода, который вызвал метод, который находится в getStackTrace()[i-1] .
Только не понятно, почему вы возвращаете [2] элемент. В вашем задании нужно вернуть имя метода, который его вызывает.
public static String method5()
В данном случае его вызовет текущий метод 5. Длину стека можно проверить вызовам метод length: Thread.currentThread().getStackTrace().length — кол-во записанных методов в Стэк, в данном случае будет 7 записей. Последним элементом будет сам метод getStacktrace() . Нам нужно вернуть метод, который его вызывает, значит нужно вернуть i-1(6). В итоге получим:
return Thread.currentThread().getStackTrace()[6].getMethodName();
return Thread.currentThread().getStackTrace()[5].getMethodName();
А вот если вы хотите вывести номер строки, вызвавший этот метод, тогда да, return Thread.currentThread().getStackTrace()[2].getLineNumber() вернет номер строки метода 4, который вызвал метод 5.
Ответ выше немного неточен. В стеке всегда метод вызвавший StackTrace , будет на позиции[2].
- 0 — getStackTrace
- 1 — имя метода (свое имя)
- 2 — имя метода кто вызвал [1]
- 3 — имя метода кто вызвал [2]
- 4 — и т.д.
Мы тут видим прошлое, что происходило до запуска текущего методa.