Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Чем плохо? По-моему нормально. Ваш вариант?
int x;
int x() {
return x;
}
@Override
public String toString() {
return "x = " + x; // x - ссылка на поле или метод x()?
}
А для чего вам нужны функции, как объекты первого рода? Можете считать java.util.function.* таким объектом первого рода. То, что ввели функциональный интерфейс это просто превосходно, т.к. позволяет использовать лямбды для огромного числа старых библиотек.
Жить и работать с этим точно можно.
А для чего вам нужны функции, как объекты первого рода?
Есть мнение, что вывод типов для всех переменных слишком опасный инструмент и даёт ухудшение читабельности кода. Я не имею четкого собственного мнения по этому поводу. но большой проблемы в этом не вижу.
А какие задачи вы хотите решать с множественным наследованием?
Чем плохо? По-моему нормально. Ваш вариант?
По-моему очень хорошо переизобрели.
Даже если забыть про C++, где двойное двоеточие широко используется для доступа к элементам неймспейса, семантика оператора для получения ссылки на метод совершенно не ясна.
…
Альтернативных вариантов куча. Самый простой, который сразу приходит в голову, это поставить амперсанд или «собачку» перед методом (&Integer.valueOf / @ Integer.valueOf) — тогда название «ссылка на метод» становится вполне интуитивным.
doSomething () {
@Annotation("Blah blah blah")
collection.forEach(@Integer.toString);
//Для меня это аннотация, либо обращение ко внутренним членам аннотации.
}
Какой то оператор (хоть символьный, хоть буквенный) перед методом имел бы смысл и читался просто…
Как я уже сказал, смысл этого оператора покрыт тайной.
Разумеется, там в API тоже тонны говна, имен, взятых из unix и шелл-скриптов, о качестве и согласованности которых можно промолчать.
.putIfAbsent? .getOrDefault? Для всех этих операций в других языках уже давно придумали более или менее устоявшийся синтаксис/названия
x = map["foo"] or 1
# x = map.get("foo") or 1
x = map.get("foo", defaultValue)x = map["foo"] or 1 # x = map.get("foo") or 1
false или 0, я бы не хотел получить единицу.Общепринятого названия здесь нет, но обычно называется getOrCompute, getOrStore и т.д. Всё-таки метод возвращает значение, а не просто кладёт его, если раньше не было.
Если вы видете putIfAbsent в первый раз за его 9.5 летнее публичное существование в стандартной либе, то увы вам. Значит вы с Java работаете эпизодически.
Я вообще не буду ожидать, что метод «put*» будет возвращать значение
Ответ прост: так сложилось в экосистеме Java и менять чего-то ради абстратного CS нет смысла.
Да нет, все это пришло из практического CS.
А вы аппелируете как раз к абстрактному.
Вы бы лучше на оператор [] в С++ std::map посмотрели ;)
Как вы назовете метод, который делает put, при этом вытесняет старое значение, и возвращает вытесненное значение, ибо другого раза получить его нет возможености — вытеснили.
Изначально меня возмутило название метода «putIfAbsent», который используется для получения значения.
AtomicLong newValue = new AtomicLong(value);
AtomicLong oldValue = map.putIfAbsent(key, newValue);
if ( oldValue != newValue ) {
result = oldValue.addAndGet(value);
}
Пример странностей в C++ не оправдывает нелогичной семантики в Java.
Если вам нужен метод, который вытесняет старое значение, ну так и назовите его «вытеснить». По-английски это очень красиво — «displace». Если хотите точного описания семантики, то назовите «putOrDisplace».
Так или иначе, я не против дополнительной функциональности в стандартных методах. Если «put» используется для добавления элементов в отображение, но при этом имеет ещё фишку в виде возврата предыдущего значения, то это нормально. Это добавляет удобства, а значит имеет смысл. Изначально меня возмутило название метода «putIfAbsent», который используется для получения значения.
get и put, лично я ожидал бы метод getOrPut. С другой стороны, в джаве метод put тоже возвращает значение, так что возвращение значения методом putIfAbsent не настолько уж неожиданно.putIfAbsent возвращает существующее значение, если оно есть, и удалённое значение, если его не было (то есть null). Вот это — сюрприз.for (Item item: somethingIterable) {
...
}
… много устаревшего и неактуального шлака времён HTML 3.2, на первых страницах поисковиков.
В этой ветке обсуждений я уже увидел, что в Java всё-таки есть нормальные способы — только где о них можно почитать в концентрированном виде, чтобы иметь дело с современными best practices, а не с привычками бородатых программеров из 90-х?
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "val" + i);
}
IntStream.range(1, 10).forEach(i -> map.put(i, "val" + i));
IntStream.range(1, 10).forEach(i -> map.put(i, "val" + i));
IntStream.range(1, 10).boxed().collect(Collectors.toMap(i -> i, i -> "val" + i));
ForkJoinPool pool = new ForkJoinPool(5);
long count = pool.submit(() -> values.parallelStream().sorted().count()).get();
Имейте в виду, что этот код останется корректным даже если убрать аннотацию @FunctionalInterface.
Но в отличии от анонимных объектов, переменная num не обязательно должна быть объявлена как final.
Запись в переменную num в пределах лямбда-выражения также запрещена.
var list = new List<int> { 1, 2, 3 };
int sum = 0;
list.ForEach(i => sum += i);JDK 1.8 содержит множество встроенных функциональных интерфейсов.
Acton<T1, ... , TN> и Func<T1, ... , TN, TResult> из шарпа, чтобы не плодить тьму бесполезных интерфейсов ради одного вызова?> int[] sum = new int[1];
> list.forEach(i -> sum[0] += i);
> return sum[0];
> IntStream s = ....
s.sum(); // PROFIT
def render = {
var name="";
def process {
//do something with name
println(name);
}
".input" #> SHtml.text(name, name=_) & //первая лямбда - модификация локальной переменной
".submit" #> SHtml.submit("Send", process _) //вторая лямбда - использует локальную переменную, сама функция см. выше
}
Почему компилятор не может заменить работу с локальной переменной работой с кучей автоматически?
Окей, заменяем запись в локальную переменную работой с кучей, как это видится наиболее прямолинейным способом — разве в этом случае кодеры (parallel+unordered) ничего не огребут? Возможность выстрелить себе в ногу сохраняется в любом случае.
List<Integer> list = Arrays.asList(1,2,3,4,5);
int sum = list.stream().mapToInt(Integer::intValue).sum();
list.Sum(). Вопрос был именно в использовании изменяемой локальной переменной.list.stream().reduce((x, y) -> x + y);
sum («очевидно» это только для функциональщиков). Оба решения слишком далеко от лаконичного list.Sum() из шарпа.FooLibrary.sum(list.stream()) (если он уже не сделан)?list.stream().reduce(Reducers::sum);
operator+ не определён для Object, а в ограничениях на тип это требование не сформулировать.Stream<Integer> stream = (List<Integer> ).stream();
stream.reduce(0/*Должен заавтобоксится в Integer*/, BinaryOperator<Integer> Reducers::sum);
//Если подставить дженерики будет
@FunctionalInterface
BinaryOperator <Integer> {
public Integer operate(Integer a, Integer b);
}
//Соответсвенно sum должен быть:
Integer sum(Integer a, Integer b) {
/*Интеджеры мы складывать умеем, если что анбокснем*/
return a + b;
}
ListExtensions.sum(list). Для этого вам даже Java 8 не нужна.Тогда какой смысл в аннотации?
Имейте в виду, что этот код останется корректным даже если убрать аннотацию @FunctionalInterface.
Тогда какой смысл в аннотации?
а если вам нужно что-то более высокоуровневое — так есть Scala/Closure/JRuby/напишите свое
в Java какая-то своя специфика, что ни лямбды, ни атрибуты, ни Linq просто не нужны
In Smalltalk, Objective-C, .NET,[7] Python, and REALbasic they are called dictionaries; in Perl and Ruby they are called hashes; in C++, Java, Go, Clojure, Scala, OCaml, Haskell they are called maps(they — Associative array)
В языке Java ассоциативный массив именуется картой(map)
Мы создаем ссылку на конструктор с помощью Person::new. Компилятор автоматически выбирает подходящий конструктор, сигнатура которого совпадает с сигнатурой PersonFactory.create.
а промежуточные операции возвращают тот же поток
Посмотрите Stream javadoc для filter,map, mapToInt, flatMap, и прочих промежуточных операций:
@return the new stream
А также в коде: return new StatelessOp<P_OUT, R>(this, ...
Те возвращается обертка над текущим потоком
Новое в Java 8