Двоеточие в цикле for java
![Двоеточие в цикле for java Двоеточие в цикле for java thumbnail](https://cdn.javarush.ru/images/article/1874d3a6-81d7-40c0-aa43-4a2fc467eb49/1024.jpeg)
Говорят, что лучший программист – ленивый программист. Вместо того, чтобы совершать однотипные действия по нескольку раз, он придумает алгоритм, который сделает эту работу за него. А еще он сделает его хорошо, чтобы не нужно было переделывать. Примерно так, чтобы много раз не писать один и тот же код, придумали циклы. Представим, что нам нужно вывести в консоль числа от 0 до 99. Код без цикла:
System.out.ln(0); System.out.ln(1); System.out.ln(2); System.out.ln(3); System.out.ln(4); System.out.ln(5); // И так далее
Этот код займет 100 строк! Очень много. А вот как это будет выглядеть с циклом:
for(int i = 0; i < 100; i++) { System.out.ln(i); }
Всего 3 строки!
Что такое циклы for?
Цикл for – это управляющая конструкция программного кода, которая нарушает линейность исполнения алгоритма и позволяет выполнить указанный код множество раз. Например, необходимо принять 30 капель лекарства. Алгоритм будет примерно такой:
- Приготовить стакан.
- Открыть крышку.
- Получить 1 каплю.
- Получить 2 каплю.…
- Получить 30 каплю.
- Закрыть лекарство.
- Принять полученную порцию.
Этот алгоритм можно объяснить гораздо быстрее:
- Приготовить стакан.
- Открыть крышку капель.
- Получить 30 капель.
- Закрыть лекарство.
- Принять полученную порцию.
Мы практически каждый день используем цикл for в разговоре с другими людьми: “…20 шагов дальше по улице…”, “…сделай 10 повторений и еще 5 в 2 раза медленнее…”, “…сделай 5 покупок в различных категориях и получи приз…” можно продолжать долго, но смысл ясен. В Java Цикл for необходим для сокращения кода и его лаконичности.
Принцип работы цикла for
For цикл используется следующим образом:
for(<начальная точка>; <условие выхода>; <операторы счетчика>) { // Тело цикла } Пример перебора цифр от 0 до 5 и вывод каждой в консоль: for(int i = 0; i < 5; i++) { System.out.ln(i); }
Вывод:
0 1 2 3 4
Если перевести данную запись на человеческий язык, получится следующее: “Создай переменную i с начальным значением 0, пока она не достигнет 5, прибавляй к ней по 1 и на каждом шаге записывай значение i в консоль.” В основе работы цикла for в Java лежат три стадии, их можно изобразить следующей схемой: Условие выхода из цикла – это булево выражение. Если оно ложно, цикл будет завершен. В примере выше переменная i увеличивается на 1. Если ее значение менее 5, цикл продолжается. Но как только i станет больше или равно 5, цикл прекратится. Оператор счетчика – выражение, которое выполняет преобразование переменной счетчика. В примере выше переменная i увеличивалась на 1. То есть цикл будет выполнен ровно 5 раз. Если оператор счетчика будет прибавлять по 2 к переменной i, результат будет иным:
for(int i = 0; i < 5; i = i + 2) { System.out.ln(i); }
Вывод:
0 2 4
Также можно умножать переменную, делить, возводить в степень, в общем, делать все, что угодно. Главное, чтобы в результате преобразования получилось число. Тело цикла – любой код, который может быть выполнен. В примере выше в теле цикла был вывод значения переменной i в консоль, однако содержимое данного тела ограничено задачей и фантазией. Обобщая всю схему, принцип данного цикла – for – следующий: код, который находится в теле цикла, будет выполнен столько раз, сколько преобразований выполнит оператор счетчика до того, как будет достигнуто условие выхода из цикла. Если задать условие выхода из цикла как true:
for(int i = 0; true; i++) { if(i % 1000000 == 0) System.out.ln(i); } System.out.ln(“Loop ended”);
То код после цикла будет помечен ошибкой unreachable ement, так как никогда не будет исполнен. Задача на смекалку: в результате запуска кода ниже будет ли выведено в консоль “Loop ended” или цикл будет выполняться бесконечно?
for(int i = 0; i > -1; i++) { if(i % 1000000 == 0) System.out.ln(i); } System.out.ln(“Loop ended”);
Ответ: будет. Переменная i рано или поздно достигнет максимального значения, а дальнейшее увеличение превратит ее в максимальное отрицательное, в результате чего условие выхода будет выполнено (i < = -1).
Цикл forEach
При работе с циклами иногда приходится перебирать массивы или коллекции. Обычно массив можно перебрать с помощью цикла for:
public void AllElements(String[] stringArray) { for(int i = 0; i < stringArray.length; i++) { System.out.ln(stringArray[i]); } }
И это правильно. Однако, для перебора всех элементов массива по очереди придумали конструкцию forEach. Ее сигнатура следующая:
for(<Тип элемента> <Имя переменной, куда будет записан очередной элемент> : <Название массива>) { // Тело цикла }
Перебрать массив строк и вывести каждую в консоль можно следующим способом:
public void AllElements(String[] stringArray) { for(String s : stringArray) { System.out.ln(s); } }
Тоже кратко и лаконично. Самое главное, нет нужды думать о счетчике и об условии выхода, все уже сделано за нас.
Как используются циклы for
А теперь рассмотрим несколько примеров использование цикла for в Java для решения разнообразных задач.
Обратный цикл (от большего к меньшему)
for(int i = 5; i > 0; i–) { System.out.ln(i); }
Вывод:
5 4 3 2 1
Несколько переменных и увеличение счетчика в теле цикла
В цикле for можно использовать несколько переменных, например их можно преобразовывать в операторе счетчика:
int a = 0; for(int i = 5; i > 0; i–, a++) { System.out.(“Шаг: ” + a + ” Значение: “); System.out.ln(i); }
Вывод:
Шаг: 0 Значение: 5 Шаг: 1 Значение: 4 Шаг: 2 Значение: 3 Шаг: 3 Значение: 2 Шаг: 4 Значение: 1
Или объявить две переменные и идти по циклу, пока они не будут равны друг другу:
for(int i = 5, j = 11; i != j; i++, j–) { System.out.ln(“i: ” + i + ” j: ” + j); }
Вывод:
i: 5 j: 11 i: 6 j: 10 i: 7 j: 9
Вряд ли это действие имеет какую-либо ценность, но знать о такой возможности полезно. В цикле for также можно создавать внутренние циклы. В этом случае количество шагов цикла будет умножаться:
for(int i = 0; i < 5; i++) { System.out.(i + ” | “); for(int j = 0; j < 5; j++) { System.out.(j + ” “); } System.out.(‘n’); }
Вывод:
0 | 0 1 2 3 4 1 | 0 1 2 3 4 2 | 0 1 2 3 4 3 | 0 1 2 3 4 4 | 0 1 2 3 4
В цикле со счетчиком j есть возможность обращаться к счетчику внешнего цикла. Благодаря этому вложенные циклы – идеальный способ обхода двумерного, трехмерного и прочих массивов:
int[][] array = { {0, 1, 2, 3, 4 }, {1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}}; for(int i = 0; i < array.length; i++) { for(int j = 0; j < array[i].length; j++) { System.out.(array[i][j] + ” “); } System.out.(‘n’); }
Вывод:
0 1 2 3 4 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7
Досрочное завершение цикла
Если при обработке цикла нужно его прервать, используйте оператор break, который останавливает работу текущего тела цикла. Все последующие итерации также пропускаются:
public void getFirstPosition(String[] stringArray, String element) { for (int i = 0; i < stringArray.length; i++) { if(stringArray[i].equals(element)) { System.out.ln(i); break; } } }
Метод выведет позицию первого искомого элемента в массиве:
String[] array = {“one”, “two”, “three”, “Jeronimo”}; getFirstPosition(array, “two”);
Вывод:
1
Бесконечный цикл
Еще один способ создать бесконечный цикл for – оставить пустой область объявления счетчика, условие выхода и оператор счетчика:
for (;;) { }
Но учти, что в большинстве случаев бесконечный цикл – свидетельство логической ошибки. У такого цикла обязательно должно быть условие выхода. На курсе JavaRush знакомство с циклами происходит на четвертом уровне обучения в первом квесте (Java Syntax). Отдельные лекции посвящены циклу for, сравнением этого цикла в Java и языке Pascal. Также в курсе есть подборка задач по этой теме.
Источник
Я бы сам посмотрел, но я даже не знаю, как это называется. Кто-нибудь может объяснить, что он делает?
Я не знал, что было несколько раз: появился. Что он делает в этом случае здесь:
public String toString() { String cardString = “”; for (PlayingCard c : this.list) // <– { cardString = cardString + c + “n”; }
Как бы вы написали это for-each цикл по-другому, чтобы не включать”:”?
12 ответов
в коде Java используется несколько мест двоеточия:
1) ярлык выпрыгивания (учебник):
label: for (int i = 0; i < x; i++) { for (int j = 0; j < i; j++) { if (something(i, j)) break label; // jumps out of the i loop } } // i.e. jumps to here
2) троичное условие (учебник):
int a = (b < 4)? 7: 8; // if b < 4, set a to 7, else set a to 8
3) для каждого цикла (учебник):
String[] ss = {“hi”, “there”} for (String s: ss) { (s); // output “hi” , and “there” on the next iteration }
4) утверждение (руководство):
int a = factorial(b); assert a >= 0: “factorial may not be less than 0”; // throws an AssertionError with the message if the condition evaluates to false
5) Дело в операторе switch (учебник):
switch (type) { case WHITESPACE: case RETURN: break; case NUMBER: (“got number: ” + value); break; default: (“syntax error”); }
6) ссылки на метод (учебник)
class Person { public ic int compareByAge(Person a, Person b) { return a.birthday.compareTo(b.birthday); }} } Arrays.sort(persons, Person::compareByAge);
168
автор: Randy Sugianto ‘Yuku’
нет оператора “двоеточие”, но двоеточие появляется в двух местах:
1: в тернарном операторе, например:
int x = bigInt ? 10000 : 50;
в этом случае тернарный оператор действует как “если” для выражений. Если bigInt истинно, то x получит 10000 назначенных ему. Если нет, то 50. Двоеточие здесь означает “еще”.
2: в цикле for-each:
double[] vals = new double[100]; //fill x with values for (double x : vals) { //do something with x }
это устанавливает x для каждого из значений в’ vals ‘ по очереди. Поэтому, если vals содержит [10, 20.3, 30,…], тогда x будет 10 на первой итерации, 20.3 на второй, и т. д.
примечание: Я говорю, что это не оператор, потому что это просто синтаксис. Он не может появиться в каком-либо заданном выражении сам по себе, и это просто случайность, что и for-each и тернарный оператор используют двоеточие.
просто добавить, когда используется в цикле for-each,”: “можно в основном читать как”in”.
Так
for (String name : names) { // remainder omitted }
следует читать ” для каждого имени в именах do …”
как бы вы написали это для каждого цикла по-разному, чтобы не включать”:”?
предполагая, что list это Collection экземпляра …
public String toString() { String cardString = “”; for (Iterator<PlayingCard> it = this.list.iterator(); it.hasNext(); /**/) { PlayingCard c = it.next(); cardString = cardString + c + “n”; } }
Я должен добавить педантичный смысл, что : не является оператором в этом контексте. Оператор выполняет операцию в выражении, а материал внутри ( … ) на for оператор не является выражением … согласно JLS.
Он используется в циклах для итерации по списку объектов.
for (Object o: list) { // o is an element of list here }
считайте это for <item> in <list> в Python.
в вашем конкретном случае,
String cardString = “”; for (PlayingCard c : this.list) // <– { cardString = cardString + c + “n”; }
this.list – это набор (список, набор или массив), и этот код назначает c для каждого элемента коллекции.
Итак, если this.list были коллекции {“2S”, “3H”, “4S”} тогда cardString на конце будет эта строка:
2S 3H 4S
1
автор: Randy Sugianto ‘Yuku’
вы обычно видите его в тернарном операторе присваивания;
синтаксис
variable = `condition ? result 1 : result 2;`
пример:
boolean isNegative = number > 0 ? false : true;
что “эквивалентно” в природе if else
if(number > 0){ isNegative = false; } else{ isNegative = true; }
кроме примеров, приведенных различными плакатами,
вы также можете использовать : для обозначения метки для блока, который вы можете использовать в сочетании с continue и break..
например:
public void some(){ //an infinite loop goBackHere: { //label for(int i = 0; i < 10 ;i++){ if(i == 9 ) continue goBackHere; } } }
он будет печатать строку “что-то” три раза.
JLabel[] labels = {new JLabel(), new JLabel(), new JLabel()}; for ( JLabel label : labels ) { label.setText(“something”); panel.add(label); }
поскольку большинство циклов for очень похожи, Java предоставляет ярлык для уменьшения количество кода, необходимого для записи цикла, называемого для каждого цикла.
вот пример краткого для каждого цикла:
for (Integer grade : quizGrades){ System.out.ln(grade); }
в приведенном выше примере двоеточие (:) можно читать как “in”. Для каждого цикла в целом можно читать как “для каждого целочисленного элемента (называемого grade) в quizGrades, распечатайте значение класса.”
Он используется в новой короткой руке для / loop
final List<String> list = new ArrayList<String>(); for (final String s : list) { System.out.ln(s); }
и тернарный оператор
list.isEmpty() ? true : false;
автор: feeling abused and harassed
двоеточие фактически существует в сочетании с ?
int minVal = (a < b) ? a : b;
эквивалентно:
int minval; if(a < b){ minval = a;} else{ minval = b; }
также в каждом цикле:
for(Node n : List l){ … }
дословно:
for(Node n = l.; n.next != null; n = n.next)
двоеточие используется в каждом цикле, Попробуйте этот пример,
import java.util.*; class ForEachLoop { public ic void main(String args[]) {`enter code here` Integer[] iray={1,2,3,4,5}; String[] sray={“ENRIQUE IGLESIAS”}; ME(iray); ME(sray); } public ic void ME(Integer[] i) { for(Integer x:i) { System.out.ln(x); } } public ic void ME(String[] i) { for(String x:i) { System.out.ln(x); } } }
автор: Saurabh Srivastava
Источник
29.12.2019Java
Оператор двойного двоеточия (: ???? , также известный как оператор ссылки на метод в Java, используется для вызова метода путем обращения к нему с помощью его класса напрямую. Они ведут себя точно так же, как лямбда-выражения. Единственное отличие, которое он имеет от лямбда-выражений, состоит в том, что здесь используется прямая ссылка на метод по имени, а не на делегирование метода.
Синтаксис:
<Class name>::<method name>
Пример: Чтобы напечатать все элементы потока:
- Используя лямбда-выражение: stream.forEach( s-> System.out.ln(s));
Программа:
import java.util.stream.*;
class GFG {
public ic void main(String[] args)
{
Stream<String> stream
= Stream.of(“Geeks”, “For”,
“Geeks”, “A”,
“Computer”,
“Portal”);
stream.forEach(s -> System.out.ln(s));
}
}
Выход:
Geeks For Geeks A Computer Portal
- Используя оператор с двоеточием: stream.forEach( System.out::ln(s));
Программа: продемонстрировать использование оператора с двойным двоеточием
import java.util.stream.*;
class GFG {
public ic void main(String[] args)
{
Stream<String> stream
= Stream.of(“Geeks”, “For”,
“Geeks”, “A”,
“Computer”,
“Portal”);
stream.forEach(System.out::ln);
}
}
Выход:
Geeks For Geeks A Computer Portal
Когда и как использовать оператор двойного двоеточия?
Ссылка на метод или оператор двойного двоеточия могут использоваться для ссылки:
- статический метод,
- метод экземпляра или
- конструктор.
Как использовать ссылку на метод в Java:
- Статический метод
Синтаксис:
(ClassName::methodName)
Пример:
SomeClass::someicMethod
Программа:
import java.util.*;
class GFG {
ic void some(String s)
{
System.out.ln(s);
}
public ic void main(String[] args)
{
List<String> list = new ArrayList<String>();
list.add(“Geeks”);
list.add(“For”);
list.add(“GEEKS”);
list.forEach(GFG::some);
}
}
Выход:
Geeks For GEEKS
- Метод экземпляра
Синтаксис:
(objectOfClass::methodName)
Пример:
System.out::ln
Программа:
import java.util.*;
class GFG {
void some(String s)
{
System.out.ln(s);
}
public ic void main(String[] args)
{
List<String> list = new ArrayList<String>();
list.add(“Geeks”);
list.add(“For”);
list.add(“GEEKS”);
list.forEach((new GFG())::some);
}
}
Выход:
Geeks For GEEKS
- Супер метод
Синтаксис:
(super::methodName)
Пример:
super::someSuperClassMethod
Программа:
import java.util.*;
import java.util..*;
class Test {
String (String str)
{
return (“Hello ” + str + “n”);
}
}
class GFG extends Test {
@Override
String (String s)
{
<String, String>
func = super::;
String newValue = func.apply(s);
newValue += “Bye ” + s + “n”;
System.out.ln(newValue);
return newValue;
}
public ic void main(String[] args)
{
List<String> list = new ArrayList<String>();
list.add(“Geeks”);
list.add(“For”);
list.add(“GEEKS”);
list.forEach(new GFG()::);
}
}
Выход:
Hello Geeks Bye Geeks Hello For Bye For Hello GEEKS Bye GEEKS
- Метод экземпляра произвольного объекта определенного типа
Синтаксис:
(ClassName::methodName)
Пример:
SomeClass::someInstanceMethod
Программа:
import java.util.*;
class Test {
String str=null;
Test(String s)
{
this.str=s;
}
void some()
{
System.out.ln(this.str);
}
}
class GFG {
public ic void main(String[] args)
{
List<Test> list = new ArrayList<Test>();
list.add(new Test(“Geeks”));
list.add(new Test(“For”));
list.add(new Test(“GEEKS”));
list.forEach(Test::some);
}
}
Выход:
Geeks For GEEKS
- Конструктор классов
Синтаксис:
(ClassName::new)
Пример:
ArrayList::new
Программа:
import java.util.*;
class GFG {
public GFG(String s)
{
System.out.ln(“Hello ” + s);
}
public ic void main(String[] args)
{
List<String> list = new ArrayList<String>();
list.add(“Geeks”);
list.add(“For”);
list.add(“GEEKS”);
list.forEach(GFG::new);
}
}
Выход:
Hello Geeks Hello For Hello GEEKS
Рекомендуемые посты:
- Ява Гуава | Метод Doubles.indexOf (double [] array, double [] target) с примерами
- Ява Гуава | Метод Doubles.indexOf (массив double [], двойная цель) с примерами
- Java.Lang.Double класс в Java
- Двойной longValue () в Java с примерами
- Инициализация двойной скобки в Java
- Двойной floatValue () в Java с примерами
- Конвертировать Double в Integer в Java
- Преобразовать строку в двойной в Java
- || оператор в Java
- новый оператор в Java
- Двойной метод doubleToLongBits () в Java с примерами
- Двойной метод isInfinite () в Java с примерами
- OptionalDouble of (double) метод в Java с примерами
- Двойной метод isNaN () в Java с примерами
- Метод Double.equals () в Java с примерами
Оператор с двоеточием (: ???? в Java
0.00 (0%) 0 votes
Источник
Я изучал источник Java 8 и нашел эту конкретную часть кода очень удивительной:
//defined in IntPipeline.java @Override public final OptionalInt reduce(IntBinaryOperator op) { return evaluate(ReduceOps.makeInt(op)); } @Override public final OptionalInt max() { return reduce(Math::max); //this is the gotcha line } //defined in Math.java public ic int max(int a, int b) { return (a >= b) ? a : b; }
Is Math::max что-то вроде указателя метода? Как нормальный ic метод преобразуется в IntBinaryOperator?
14 ответов
обычно, можно было бы назвать reduce способ использования Math.max(int, int) следующим образом:
reduce(new IntBinaryOperator() { int applyAsInt(int left, int right) { return Math.max(left, right); } });
это требует много синтаксиса для простого вызова Math.max. Вот где лямбда-выражения вступают в игру. Начиная с Java 8 разрешено делать то же самое намного короче:
reduce((int left, int right) -> Math.max(left, right));
как это работает? Компилятор Java “обнаруживает”, что вы хотите реализовать метод, который принимает два intS и возвращает один int. Это эквивалентно формальным параметрам единственного метода интерфейса IntBinaryOperator (параметр метода reduce хотите называйте). Поэтому компилятор делает все остальное за вас-он просто предполагает, что вы хотите реализовать IntBinaryOperator.
, а как Math.max(int, int) сам выполняет формальные требования IntBinaryOperator, его можно использовать сразу. Поскольку Java 7 не имеет синтаксиса, который позволяет передавать сам метод в качестве аргумента (вы можете передавать только результаты метода, но никогда не ссылки на метод),:: синтаксис был введено в Java 8 для ссылок на методы:
reduce(Math::max);
обратите внимание, что это будет интерпретироваться компилятором, а не в JVM во время выполнения! Хотя он создает разные байт-коды для всех трех фрагментов кода, они семантически равны, поэтому последние две можно считать короткими (и, вероятно, более эффективными) версиями IntBinaryOperator над реализацией!
(см. Также перевод лямбда-выражения)
:: называется ссылкой на метод. Это в основном ссылка на один метод. Т. е. он ссылается на существующий метод по имени.
Краткое Описание:
Ниже приведен пример ссылки на статический метод:
class Hey { public ic double square(double num){ return Math.pow(num, 2); } } <Double, Double> square = Hey::square; double ans = square.apply(23d);
square может передаваться так же, как ссылки на объекты и срабатывать при необходимости. Фактически, его можно так же легко использовать как ссылку на” нормальные ” методы объектов, как ic те. Для пример:
class Hey { public double square(double num) { return Math.pow(num, 2); } } Hey hey = new Hey(); <Double, Double> square = hey::square; double ans = square.apply(23d);
выше функционального интерфейса. Чтобы полностью понять :: важно также понимать функциональные интерфейсы. Ясно, а функционального интерфейса – это интерфейс с одним абстрактным методом.
примеры функциональных интерфейсов включает Runnable, Callable и ActionListener.
выше функциональный интерфейс с одним методом: apply. Он берет одну аргумент и дает результат.
почему ::s являются удивительными это это:
ссылки на метод-это выражения, которые имеют ту же обработку, что и лямбда-выражения (…), но вместо предоставления тела метода они ссылаются на существующий метод по имени.
Е. Г. вместо того, чтобы писать лямбда тела
<Double, Double> square = (Double x) -> x * x;
вы можете просто сделать
<Double, Double> square = Hey::square;
во время выполнения этих двух square методы ведут себя точно так же, как и друг друга. Байт-код может быть или не быть одинаковым (хотя в приведенном выше случае генерируется тот же байт-код; скомпилируйте выше и проверьте с помощью javap -c).
единственным основным критерием для удовлетворения является:метод, который вы предоставляете, должен иметь аналогичную подпись методу функционального интерфейса, который вы используете в качестве ссылки на объект.
ниже незаконно:
Supplier<Boolean> p = Hey::square; // illegal
square принимает аргумент и возвращает double. The get метод ожидает аргумента, но ничего не возвращает. Таким образом, это приводит к ошибке.
ссылка на метод относится к методу функционального интерфейса. (как уже упоминалось, функциональные интерфейсы могут иметь только один способ каждый).
еще несколько примеров:accept метод потребитель принимает ввод, но ничего не возвращает.
Consumer<Integer> b1 = System::exit; // void exit(int us) Consumer<String[]> b2 = Arrays::sort; // void sort(Object[] a) Consumer<String> b3 = MyProgram::main; // void main(String… args) class Hey { public double getRandom() { return Math.random(); } } Callable<Double> call = hey::getRandom; Supplier<Double> call2 = hey::getRandom; DoubleSupplier sup = hey::getRandom; // Supplier is al interface that takes no argument and gives a result
выше getRandom не принимает аргументов и возвращает double. Таким образом, любой функциональный интерфейс, удовлетворяющий критериям:не принимайте никаких аргументов и возвращайтесь double можно использовать.
еще пример:
Set<String> set = new HashSet<>(); set.addAll(Arrays.asList(“leo”,”bale”,”hanks”)); Predicate<String> pred = set::contains; boolean exists = pred.test(“leo”);
в случае параметризованных типов:
class Param<T> { T elem; public T get() { return elem; } public void set(T elem) { this.elem = elem; } public ic <E> E returnSame(E elem) { return elem; } } Supplier<Param<Integer>> obj = Param<Integer>::new; Param<Integer> param = obj.get(); Consumer<Integer> c = param::set; Supplier<Integer> s = param::get; <String, String> func = Param::<String>returnSame;
ссылки на методы могут иметь разные стили, но в основном все они означают то же самое и может быть просто визуализировано как лямбда:
- статический метод (ClassName::methName)
- метод экземпляра определенного объекта (instanceRef::methName)
- супер метод конкретного объекта (super::methName)
- метод экземпляра произвольного объекта определенного типа (ClassName::methName)
- ссылка на конструктор класса (ClassName::new)
- ссылка на конструктор массива (TypeName[]::new)
для получения дополнительной информации см. https://cr.openjdk.java.net / ~briangoetz/lambda/lambda-e-final.html.
Да, это правда. The :: оператор используется для ссылки на метод. Итак, можно извлечь ic методы из классов, используя его или методы из объектов. Один и тот же оператор может использоваться даже для конструкторов. Все случаи, упомянутые здесь, приведены в примере кода ниже.
официальная документация от Oracle может быть найдена здесь.
вы можете иметь лучший обзор изменений JDK 8 в этой статьи. В метод/конструктор ссылок раздел пример кода также предоставляется:
interface ConstructorReference { T constructor(); } interface MethodReference { void anotherMethod(String input); } public class ConstructorClass { String value; public ConstructorClass() { value = “default”; } public ic void method(String input) { System.out.ln(input); } public void nextMethod(String input) { // operations } public ic void main(String… args) { // constructor reference ConstructorReference reference = ConstructorClass::new; ConstructorClass cc = reference.constructor(); // ic method reference MethodReference mr = cc::method; // object method reference MethodReference mr2 = cc::nextMethod; System.out.ln(cc.value); } }
:: – новый оператор, включенный в Java 8, который используется для ссылки на метод существующего класса. Вы можете ссылаться на статические методы и нестатические методы класса.
для ссылки на статические методы синтаксис:
ClassName :: methodName
для ссылки на нестатические методы синтаксис
objRef :: methodName
и
ClassName :: methodName
единственным предварительным условием для ссылки на метод является то, что метод существует в функциональном интерфейсе, который должен быть совместим с ссылка на метод.
ссылки на метод при оценке создают экземпляр функционального интерфейса.
найдено на:https://www.speakingcs.com/2014/08/method-references-in-java-8.html
это ссылка на метод в Java 8. Документация oracle является здесь.
Как указано в документации…
метод reference Person:: compareByAge является ссылкой на статический метод.
ниже приведен пример ссылки на метод экземпляра конкретный объект:
class ComparisonProvider { public int compareByName(Person a, Person b) { return a.getName().compareTo(b.getName()); } public int compareByAge(Person a, Person b) { return a.getBirthday().compareTo(b.getBirthday()); } } ComparisonProvider myComparisonProvider = new ComparisonProvider(); Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
ссылка на метод myComparisonProvider:: compareByName вызывает метод compareByName это часть объекта myComparisonProvider. Среда JRE выводит аргументы типа метода, которые в данном случае являются (Person, Person).
кажется, немного поздно, но вот мои два цента. А лямбда-выражение используется для создания анонимных методов. Он ничего не делает, кроме вызова существующего метода, но яснее ссылаться на метод непосредственно по его имени. И справочник по методу позволяет нам сделать это с помощью оператора method-reference :: .
рассмотрим следующий простой класс, где каждый сотрудник имеет имя и класс.
public class Employee { private String name; private String grade; public Employee(String name, String grade) { this.name = name; this.grade = grade; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGrade() { return grade; } public void setGrade(String grade) { this.grade = grade; } }
Предположим, у нас есть список сотрудники возвращаются каким-то методом, и мы хотим отсортировать сотрудников по их классу. Мы знаем, что можем использовать анонимный класс as:
List<Employee> employeeList = getDummyEmployees(); // Using anonymous class employeeList.sort(new Comparator<Employee>() { @Override public int compare(Employee e1, Employee e2) { return e1.getGrade().compareTo(e2.getGrade()); } });
где getDummyEmployee() метод так:
private ic List<Employee> getDummyEmployees() { return Arrays.asList(new Employee(“Carrie”, “C”), new Employee(“Farhan”, “F”), new Employee(“Brian”, “B”), new Employee(“Donald”, “D”), new Employee(“Adam”, “A”), new Employee(“Evan”, “E”) ); }
теперь мы знаем, что компаратор функциональный интерфейс. А Функционального Интерфейса – это тот, у которого есть ровно один абстрактный метод (хотя он может содержать один или несколько стандартных или статических методов). Поэтому мы можем использовать лямбда выражение как:
employeeList.sort((e1,e2) -> e1.getGrade().compareTo(e2.getGrade())); // lambda exp
вроде все хорошо, но что если класс Employee также предоставляет аналогичный метод:
public class Employee { private String name; private String grade; // getter and setter public ic int compareByGrade(Employee e1, Employee e2) { return e1.grade.compareTo(e2.grade); } }
в этом случае использование самого имени метода будет более понятным. Следовательно, мы можем напрямую ссылаться на метод, используя ссылку на метод как:
employeeList.sort(Employee::compareByGrade); // method reference
по состоянию на docs существует четыре вида ссылок на метод:
+—-+——————————————————-+————————————–+ | | Kind | Example | +—-+——————————————————-+————————————–+ | 1 | Reference to a ic method | ContainingClass::icMethodName | +—-+——————————————————-+————————————–+ | 2 |Reference to an instance method of a particular object | containingObject::instanceMethodName | +—-+——————————————————-+————————————–+ | 3 | Reference to an instance method of an arbitrary object| ContainingType::methodName | | | of a particular type | | +—-+——————————————————-+————————————–+ | 4 |Reference to a constructor | ClassName::new | +————————————————————+————————————–+
:: оператор был введен в java 8 для ссылок на методы. Ссылка на метод-это сокращенный синтаксис для лямбда-выражения, которое выполняет только один метод. Вот общий синтаксис ссылки на метод:
Object :: methodName
мы знаем, что мы можем использовать лямбда-выражения вместо использования анонимного класса. Но иногда лямбда-выражение на самом деле просто вызов некоторого метода, например:
Consumer<String> c = s -> System.out.ln(s);
сделать код более ясным, вы можете превратить это лямбда-выражение в ссылку на метод:
Consumer<String> c = System.out::ln;
the :: известен как ссылки на метод. Допустим, мы хотим вызвать метод calculatePrice покупки класса. Тогда мы можем написать так:
Purchase::calculatePrice
Это также можно рассматривать как короткую форму записи лямбда-выражения, поскольку ссылки на метод преобразуются в лямбда-выражения.
во время выполнения они ведут себя точно так же.Байт-код может / не быть одинаковым (для вышеуказанного Incase он генерирует тот же байт-код(complie выше и проверяет javaap-c;))
во время выполнения они ведут себя точно так же.метод (math:: max);, он генерирует ту же математику (компли выше и проверяет javap-c;))
return reduce(Math::max); и НЕ РАВНО to return reduce(max());
но это значит, что-то вроде этого:
IntBinaryOperator myLambda = (a, b)->{(a >= b) ? a : b};//56 keystrokes I had to type -_- return reduce(myLambda);
можно просто сохранить 47 клавиш если вы пишете так
return reduce(Math::max);//Only 9 keystrokes ^_^
в java-8 Streams Reducer в simple works-это функция, которая принимает два значения в качестве входных и возвращает результат после некоторого вычисления. этот результат подается на следующей итерации.
в случае функции Math: max метод продолжает возвращать максимум двух переданных значений, и в конце концов у вас есть наибольшее число в руке.
так как многие ответы здесь объясняются хорошо :: поведение, кроме того, я хотел бы пояснить, что :: оператор не должен иметь точно такую же сигнатуру, как ссылающийся функциональный интерфейс, если он используется, например, переменные. Предположим, нам нужно BinaryOperator, который имеет вид TestObject. Традиционным способом его реализовали следующим образом:
BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() { @Override public TestObject apply(TestObject t, TestObject u) { return t; } };
как вы видите в анонимной реализации требует два аргумента TestObject и возвращает объект TestObject. Чтобы выполнить это условие, используйте :: оператор мы можем начать со статическим методом:
public class TestObject { public ic final TestObject testic(TestObject t, TestObject t2){ return t; } }
а потом звоните:
BinaryOperator<TestObject> binary = TestObject::testic;
Ok он скомпилирован нормально. Что, если нам нужен метод экземпляра? Позволяет обновить TestObject с помощью метода экземпляра:
public class TestObject { public final TestObject testInstance(TestObject t, TestObject t2){ return t; } public ic final TestObject testic(TestObject t, TestObject t2){ return t; } }
теперь мы можем получить доступ к экземпляру, как показано ниже:
TestObject testObject = new TestObject(); BinaryOperator<TestObject> binary = testObject::testInstance;
этот код компилируется нормально, но ниже одного не:
BinaryOperator<TestObject> binary = TestObject::testInstance;
мое затмение скажи мне ” не удается сделать статическую ссылку на нестатический метод testInstance (TestObject, TestObject) из типа TestObject …”
справедливо его метод экземпляра, но если мы перегрузим testInstance как показано ниже:
public class TestObject { public final TestObject testInstance(TestObject t){ return t; } public final TestObject testInstance(TestObject t, TestObject t2){ return t; } public ic final TestObject testic(TestObject t, TestObject t2){ return t; } }
и звонок:
BinaryOperator<TestObject> binary = TestObject::testInstance;
код будет компилировать просто отлично. Потому что это вызовет testInstance С одним параметром вместо двойной. Хорошо, так что случилось, наши двое? параметр? Давайте распечатаем и посмотрим:
public class TestObject { public TestObject() { System.out.ln(this.hashCode()); } public final TestObject testInstance(TestObject t){ System.out.ln(“Test instance called. this.hashCode:” + this.hashCode()); System.out.ln(“Given parameter hashCode:” + t.hashCode()); return t; } public final TestObject testInstance(TestObject t, TestObject t2){ return t; } public ic final TestObject testic(TestObject t, TestObject t2){ return t; } }
что будет на выходе:
1418481495 303563356 Test instance called. this.hashCode:1418481495 Given parameter hashCode:303563356
ОК, поэтому JVM достаточно умен, чтобы вызвать param1.testInstance (param2). Можем ли мы использовать testInstance из другого ресурса, но не TestObject, т. е.:
public class TestUtil { public final TestObject testInstance(TestObject t){ return t; } }
и звонок:
BinaryOperator<TestObject> binary = TestUtil::testInstance;
он просто не будет компилироваться, и компилятор скажет: ” тип TestUtil не определяет testInstance (TestObject, TestObject)”. Поэтому компилятор будет искать статическую ссылку если это не один и тот же тип. Хорошо, а как насчет полиморфизма? Если мы удалим окончательные модификаторы и добавим наши SubTestObject класс:
public class SubTestObject extends TestObject { public final TestObject testInstance(TestObject t){ return t; } }
и звонок:
BinaryOperator<TestObject> binary = SubTestObject::testInstance;
он также не будет компилироваться, компилятор все равно будет искать статическую ссылку. Но ниже код будет компилироваться отлично, так как он проходит is-a test:
public class TestObject { public SubTestObject testInstance(Object t){ return (SubTestObject) t; } } BinaryOperator<TestObject> binary = TestObject::testInstance;
*я просто учусь, поэтому я понял, попробуйте и посмотрите, не стесняйтесь поправлять меня, если я неправильно!–28–>
нашел этот источник очень интересно.
на самом деле, это лямда – превращается в Двойной. Двоеточие более читаемо. Мы следуем этим шагам:
Шаг 1:
// We create a comparator of two persons Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());
Шаг 2:
// We use the interference Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());
Шаг 3:
// The magic Comparator c = Comparator.comparing(Person::getAge());
в старых версиях Java вместо”:: “или lambd вы можете использовать:
public interface Action { void execute(); } public class ActionImpl implements Action { @Override public void execute() { System.out.ln(“execute with ActionImpl”); } } public ic void main(String[] args) { Action action = new Action() { @Override public void execute() { System.out.ln(“execute with anonymous class”); } }; action.execute(); //or Action actionImpl = new ActionImpl(); actionImpl.execute(); }
или переход к методу:
public ic void doSomething(Action action) { action.execute(); }
1
автор: Kamil Tomasz Jarmusik
Источник