6 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Функциональное программирование: в Java и C# слишком много церемоний

Функциональное программирование в C#

Функциональное программирование
Изучаю функции на python, необходима ваша помощь. Что не так в коде? Где? Почему? Зачем? Прошу.

Функциональное программирование
Суть моего задания: найти локальный максимум в вручную заданном массиве. Я написал код в.

Функциональное программирование
Читал или слышал, что те, кто выучил ООП, потом не могут изучить функциональное программирование.

Функциональное программирование
Написать функцию, которая запрашивает у пользователя ФИО студента группы (список группы составлен.

— На ваш взгляд, следует ли человеку, который долгое время занимается объектно-ориентированным программированием, знакомиться/переходить на функциональное?

Вагиф Абилов: Вопрос полного перехода — это вопрос довольно прагматичный. А знакомиться, да, конечно же стоит.

Если мы посмотрим на объектно-ориентированные языки типа Java или C#, то они претерпели достаточно большие изменения в последние годы. Если я ничего не путаю, в C# версии 3.0, когда появился LINQ, появились лямбда-выражения, это был уже заметный ход в сторону внедрения элементов функционального программирования.

Возникает такой аргумент: «а зачем мне изучать сами функциональные языки, если мы многое можем сделать и в C# с элементами функциональных языков?». По крайней мере один из ответов на это уходит в область изменяемости структур данных, поскольку и C#, и Java всегда останутся языками с мутациями. Когда данные, которые вы определяете по-умолчанию, доступны для изменении, то, какие бы элементы функционального программирования вы не вносили, принципиальной сущности этих языков это не изменит. В последних версиях C# вы можете «играться» с элементами ФП, но, конечно же, имеет смысл попробовать поработать с настоящим функциональным языком, таким как Erlang, Haskel или F#. Последний я бы особенно рекомендовал, поскольку это язык очень хорошо встраивается в .NET.

Из статьи на Хабре.
5 мая 2017
Функциональное программирование: в Java и C# слишком много церемоний

Основные принципы программирования: функциональное программирование

Основные принципы программирования: функциональное программирование

    Переводы , 23 января 2017 в 13:43

Если вы такой же разработчик, как и я, то наверняка сперва изучали парадигму ООП. Первым вашим яыком были Java или C++ — или, если вам повезло, Ruby, Python или C# — поэтому вы наверняка знаете, что такое классы, объекты, экземпляры и т.д. В чём вы точно не особо разбираетесь, так это в основах той странной парадигмы, называющейся функциональным программированием, которая существенно отличается не только от ООП, но и от процедурного, прототипно-ориентированного и других видов программирования.

Функциональное программирование становится популярным — и на то есть причины. Сама парадигма не нова: Haskell, пожалуй, является самым функциональным языком, а возник он в 90-ых. Такие языки, как Erlang, Scala, Clojure также попадают под определение функциональных. Одним из основных преимуществ функционального программирования является возможность написания программ, работающих конкурентно (если вы уже забыли, что это — освежите память прочтением статьи о конкурентности), причём без ошибок — то есть взаимные блокировки и потокобезопасность вас не побеспокоят.

У функционального программирования есть много преимуществ, но возможного максимального использования ресурсов процессора благодаря конкурентному поведению — это его главный плюс. Ниже мы рассмотрим основные принципы функционального программирования.

Вступление: Все эти принципы не обязательны (многие языки следуют им не полностью). Все они теоретические и нужны для наиболее точного определения функциональной парадигмы.

1. Все функции — чистые

Это правило безусловно является основным в функциональном программировании. Все функции являются чистыми, если они удовлетворяют двум условиям:

  1. Функция, вызываемая от одних и тех же аргументов, всегда возвращает одинаковое значение.
  2. Во время выполнения функции не возникают побочные эффекты.

Первое правило понятно — если я вызываю функцию sum(2, 3) , то ожидаю, что результат всегда будет равен 5. Как только вы вызываете функцию rand() , или обращаетесь к переменной, не определённой в функции, чистота функции нарушается, а это в функциональном программировании недопустимо.

Второе правило — никаких побочных эффектов — является более широким по своей природе. Побочный эффект — это изменение чего-то отличного от функции, которая исполняется в текущий момент. Изменение переменной вне функции, вывод в консоль, вызов исключения, чтение данных из файла — всё это примеры побочных эффектов, которые лишают функцию чистоты. Может показаться, что это серьёзное ограничение, но подумайте ещё раз. Если вы уверены, что вызов функции не изменит ничего “снаружи”, то вы можете использовать эту функцию в любом сценарии. Это открывает дорогу конкурентному программированию и многопоточным приложениям.

2. Все функции — первого класса и высшего порядка

Эта концепция — не особенность ФП (она используется в Javascript, PHP и других языках) — но его обязательное требование. На самом деле, на Википедии есть целая статья, посвящённая функциям первого класса. Для того, чтобы функция была первоклассной, у неё должна быть возможность быть объявленной в виде переменной. Это позволяет управлять функцией как обычным типом данных и в то же время исполнять её.

Функции высшего порядка же определяются как функции, принимающие другую функцию как аргумент или возвращающие функцию. Типичными примерами таких функций являются map и filter.

3. Переменные неизменяемы

Тут всё просто. В функциональном программировании вы не можете изменить переменную после её инициализации. Вы можете создавать новые, но не можете изменять существующие — и благодаря этому вы можете быть уверены, что никакая переменная не изменится.

4. Относительная прозрачность функций

Сложно дать корректное определение относительной прозрачности. Самым точным я считаю такое: если вы можете заменить вызов функции на возвращаемое значение, и состояние при этом не изменится, то функция относительно прозрачна. Это, быть может, очевидно, но я приведу пример.

Пусть у нас есть Java-функция, которая складывает 3 и 5:

Очевидно, что любой вызов этой функции можно заменить на 8 — значит, функция относительно прозрачна. Вот пример непрозрачной функции:

Эта функция ничего не возвращает, но печатает текст, и при замене вызова функции на ничто состояние консоли будет другим — значит, функция не является относительно прозрачной.

5. Функциональное программирование основано на лямбда-исчислении

Функциональное программирование сильно опирается на математическую систему, называющуюся лямбда-исчислением. Я не математик, поэтому я не буду углубляться в детали — но я хочу обратить внимание на два ключевых принципа лямбда-исчисления, которые формируют самое понятие функционального программирования:

  1. В лямбда-исчислении все функции могут быть анонимными, поскольку единственная значимая часть заголовка функции — это список аргументов.
  2. При вызове все функции проходят процесс каррирования. Он заключается в следующем: если вызывается функция с несколькими аргументами, то сперва она будет выполнена лишь с первым аргументом и вернёт новую функцию, содержащую на 1 аргумент меньше, которая будет немедленно вызвана. Этот процесс рекурсивен и продолжается до тех пор, пока не будут применены все аргументы, возвращая финальный результат. Поскольку функции являются чистыми, это работает.

Как я уже говорил, лямбда-исчисление на этом не заканчивается — но мы рассмотрели лишь ключевые аспекты, связанные с ФП. Теперь, в разговоре о функциональном программировании вы сможете блеснуть словечком “лямбда-исчисление”, и все подумают, что вы шарите 🙂

Заключение

Функциональное программирование серьёзно напрягает мозги — но это очень мощный подход, и я считаю, что его популярность будет только расти.

Если вы хотите узнать о функциональном программировании побольше, то советуем вам ознакомиться с примерами использования принципов ФП в JavaScript (часть 1, часть 2), а также с циклом статей, посвящённым функциональному C#.

5 языков, которые следует выучить после Java

Вот 5 языков программирования, которые после Java произведут наименьший негативный эффект:

C# — язык, с которым так или иначе сталкивался любой выпускник кафедры программирования (тем более опытный разработчик). Именно поэтому многие согласятся, что, не считая языков, транслируемых в JVM, это наиболее схожий представитель. Кроме того, C# востребован, а это важное условие, если вы собираетесь монетизировать свои знания.

Что общего: очень сложно удержаться от цитирования статьи на Википедии, поэтому вот вам факты.

Оба языка так или иначе являются развитием C++. Более того, создатели C# называют свой язык развитием Java. Кроме того, оба языка строго следуют принципам ООП.

А еще у них похожий синтаксис:

public class HelloWorld
<
public static void main(String[] args) <
System.out.println(“Hello World!”);
>
>

// HelloWorld.cs
public class HelloWorld
<
public static void Main()
<
System.Console.WriteLine(“Hello World!”);
>
>

И у Java, и у C# типизация строгая, что в известной степени способствует повышению безопасности в области использования памяти. Еще у языков похожие алгоритмы сборки мусора. Ещё один важный схожий момент, прекрасно характеризующий оба языка. Наконец, оба они кроссплатформенны. Изучение этого языка рекомендуем начать с нашего базового интенсива по Си Шарп.

От чего захочется ругаться: Microsoft и естественная завязанность на их экосистему.

Swift

Если вы изучили Java для разработки мобильных приложений, то Swift станет логичным карьерным развитием. Более того, не так давно слухи упорно связывали будущее платформы Android со Swift, однако в итоге Google отстояло свое право на использование Java. Впрочем, кто поставит свой компьютер на то, что в дальнейшем Google не свернет с этого курса? В любом случае, умение писать “правильные” приложения для iOS лишним точно не будет.

Что общего: оба языка статически типизированы, оба имеют наследственную связь с С, схожие принципы наследования, перегрузки методов, протоколы и т.д. В конце-концов, на сегодняшний день это два главных мобильных языковых лагеря.

От чего хочется ругаться: подобно C#, экосистема Apple может вызывать отторжение.

Kotlin

Сахар для синтаксиса — распространенное мнение относительно Kotlin у разработчиков Java, ознакомившихся с ним лишь поверхностно. Куда более совершенный язык и наиболее очевидный преемник Java из существующих — утверждают люди, посвятившие изучению Kotlin чуть больше времени. В любом случае, как бы не сложилось ваше знакомство, равнодушным останитесь вряд ли.

Что общего: создатели не скрывают, что Kotlin является доработкой Java с перспективой полного замещения. То есть фактически Kotlin сочетает всё то, за что вы полюбили Java, но при этом ещё удобнее, безопаснее и функциональнее. Работает с виртуальной машиной JVM.

От чего хочется ругаться: и кому нужна Java, если есть Kotlin?

Python

Изучить Python после Java стоит хотя бы потому, что это просто. Во всех рейтингах, опросах и статьях, посвящённых выбору первого языка программирования, Python неизменно находится в топе.

Читать еще:  Какие антивирусы используются в современных межсетевых экранах

Что общего: практически ничего, кроме некоторых общих принципов ООП и кроссплатформености.

От чего хочется ругаться: слишком далеко от привычного понимания о программировании.

Возвращаясь к теме возможного отказа Google от Java в своем мобильном будущем, стоит всерьез рассмотреть вариант развития событий, при котором наследником станет Go. Пока что язык здорово проявляет себя в привычной среде Big Data, то есть сегодня, как минимум, Go может послужить полезным расширением для функциональности вашего приложения. Но если Go продолжит развиваться заданными темпами, а Google решится на внутреннюю революцию, то знание этого языка станет не бонусом, а практически необходимостью. Кстати, пару лет назад один из создателей Go, выложил в сеть интересную презентацию с названием “Go для Java-программистов”. Рекомендуется к просмотру.

Что общего: формально общего здесь примерно столько же, сколько и в случае с C#: происхождение от языка C, строгая типизация, алгоритмы очистки памяти, схожие методы, интерфейсы и многое другое. Но, как язык, созданный почти через 15 лет после Java и через 10 после C#, Go он куда совершеннее, функциональнее и перспективнее.

От чего хочется ругаться: несмотря на то, что язык Go не вчера был придуман, при углубленном изучении вы неизбежно столкнетесь с некоторыми недоработками.

Java — один из самых популярных языков современности и прекрасный инструмент для того, чтобы зарабатывать на жизнь. Но даже истинные ценители Java иногда испытывают непреодолимое желание попробовать что-то новое, пусть даже с осознанием того, что в процессе обучения придется плеваться и морщиться.

Вот 5 языков программирования, которые после Java произведут наименьший негативный эффект:

C# — язык, с которым так или иначе сталкивался любой выпускник кафедры программирования (тем более опытный разработчик). Именно поэтому многие согласятся, что, не считая языков, транслируемых в JVM, это наиболее схожий представитель. Кроме того, C# востребован, а это важное условие, если вы собираетесь монетизировать свои знания.

Что общего: очень сложно удержаться от цитирования статьи на Википедии, поэтому вот вам факты.

Оба языка так или иначе являются развитием C++. Более того, создатели C# называют свой язык развитием Java. Кроме того, оба языка строго следуют принципам ООП.

А еще у них похожий синтаксис:

public class HelloWorld
<
public static void main(String[] args) <
System.out.println(“Hello World!”);
>
>

// HelloWorld.cs
public class HelloWorld
<
public static void Main()
<
System.Console.WriteLine(“Hello World!”);
>
>

И у Java, и у C# типизация строгая, что в известной степени способствует повышению безопасности в области использования памяти. Еще у языков похожие алгоритмы сборки мусора. Ещё один важный схожий момент, прекрасно характеризующий оба языка. Наконец, оба они кроссплатформенны. Изучение этого языка рекомендуем начать с нашего базового интенсива по Си Шарп.

От чего захочется ругаться: Microsoft и естественная завязанность на их экосистему.

Swift

Если вы изучили Java для разработки мобильных приложений, то Swift станет логичным карьерным развитием. Более того, не так давно слухи упорно связывали будущее платформы Android со Swift, однако в итоге Google отстояло свое право на использование Java. Впрочем, кто поставит свой компьютер на то, что в дальнейшем Google не свернет с этого курса? В любом случае, умение писать “правильные” приложения для iOS лишним точно не будет.

Что общего: оба языка статически типизированы, оба имеют наследственную связь с С, схожие принципы наследования, перегрузки методов, протоколы и т.д. В конце-концов, на сегодняшний день это два главных мобильных языковых лагеря.

От чего хочется ругаться: подобно C#, экосистема Apple может вызывать отторжение.

Kotlin

Сахар для синтаксиса — распространенное мнение относительно Kotlin у разработчиков Java, ознакомившихся с ним лишь поверхностно. Куда более совершенный язык и наиболее очевидный преемник Java из существующих — утверждают люди, посвятившие изучению Kotlin чуть больше времени. В любом случае, как бы не сложилось ваше знакомство, равнодушным останитесь вряд ли.

Что общего: создатели не скрывают, что Kotlin является доработкой Java с перспективой полного замещения. То есть фактически Kotlin сочетает всё то, за что вы полюбили Java, но при этом ещё удобнее, безопаснее и функциональнее. Работает с виртуальной машиной JVM.

От чего хочется ругаться: и кому нужна Java, если есть Kotlin?

Python

Изучить Python после Java стоит хотя бы потому, что это просто. Во всех рейтингах, опросах и статьях, посвящённых выбору первого языка программирования, Python неизменно находится в топе.

Что общего: практически ничего, кроме некоторых общих принципов ООП и кроссплатформености.

От чего хочется ругаться: слишком далеко от привычного понимания о программировании.

Возвращаясь к теме возможного отказа Google от Java в своем мобильном будущем, стоит всерьез рассмотреть вариант развития событий, при котором наследником станет Go. Пока что язык здорово проявляет себя в привычной среде Big Data, то есть сегодня, как минимум, Go может послужить полезным расширением для функциональности вашего приложения. Но если Go продолжит развиваться заданными темпами, а Google решится на внутреннюю революцию, то знание этого языка станет не бонусом, а практически необходимостью. Кстати, пару лет назад один из создателей Go, выложил в сеть интересную презентацию с названием “Go для Java-программистов”. Рекомендуется к просмотру.

Что общего: формально общего здесь примерно столько же, сколько и в случае с C#: происхождение от языка C, строгая типизация, алгоритмы очистки памяти, схожие методы, интерфейсы и многое другое. Но, как язык, созданный почти через 15 лет после Java и через 10 после C#, Go он куда совершеннее, функциональнее и перспективнее.

От чего хочется ругаться: несмотря на то, что язык Go не вчера был придуман, при углубленном изучении вы неизбежно столкнетесь с некоторыми недоработками.

Выбор первого языка программирования — обзор Java

На сегодняшний день самым популярным языком программирования является Java. При этом он продолжает набирать обороты.

Попытаемся разобраться почему Java выбирается в современных проектах в качестве основного языка программирования.

Си-подобный синтаксис*

В то время, когда создавался язык Java, самым популярным языком программирования был C++. Для того, чтобы «переманить» программистов на новый Java было принято решение сделать его максимально похожим на С++, взяв по возможности лучшее от него.

Java и С++ не единственные, кто обладает подобным синтаксисом. Прародителем C++ был язык C (Си), потому все языки использующие подобный синтаксис называются си-подобными, и их существует великое множество (Wikipedia: C-family).

Таким образом если вы уже знакомы хотя бы с одним из этих языков, то обилие точек, фигурных и круглых скобок в Java покажутся вам чем-то давно знакомым и привычным. С другой стороны изучив синтаксис Java вам будет гораздо проще постигнуть и остальные языки этого семейства.

* Синтаксис — это набор правил, которым должен соответствовать текст программы. По-простому: то, как выглядит программа. Более сложно – на вики.

Язык общего назначения

По своему назначению языки программирования бывают:

  • специальные (решающие задачи в определённой отрасли. Например, в математике Fortran, в базах данных SQL);
  • общего назначения (решающие широкий спектр задач в любых отраслях. Например С++, Java, C#).

Java относится ко второму типу – это язык общего назначения, на котором можно написать практически любую программу. На сегодняшний день на Java создаются программы любого уровня сложности: от программирования бытовой техники и мобильных устройств (Java ME) до сложных высоко нагруженных сервисов (Java EE).

  • универсален, решает любые задачи
  • в отдельных отраслях уступает (по скорости работы и удобству использования) специализированным языкам

Объектно-ориентированный

Все компьютерные программы пытаются описать процессы нашего мира в командах процессора. Поскольку компьютер ничего не знает об объектах нашего мира, программисту всегда приходилось «переводить» всё на язык цифр и инструкций. Так было до 70-х годов, пока не появилась объектно ориентированная парадигма программирования. С её помощью оказалось возможным программирование на уровне объектов из нашего мира, а не на уровне цифр из мира компьютерного.

Например, вот так выглядит описание двух столов в не-объектном виде:

  • длина первого стола: 1200 мм
  • ширина первого стола: 500 мм
  • высота первого стола: 1000 мм
  • длина второго стола: 1300 мм
  • ширина второго стола: 600 мм
  • высота второго стола: 1100 мм

Между параметрами нет никакой связи, кроме их названий. Можно легко допустить ошибку в попытке посчитать площадь стола: умножить длину ПЕРВОГО стола на ширину ВТОРОГО.

Пример объектно-ориентированного описания:

  • длина: 1200 мм
  • ширина: 500 мм
  • высота: 1000 мм
  • длина: 1300 мм
  • ширина: 600 мм
  • высота: 1100 мм

В данном случае, мы уже оперируем не разрозненными параметрами, а целыми объектами: Первый стол и Второй стол.

Программы, написанные на объектно-ориентированных языках, выполнялись медленней. Это было основной причиной, почему эта парадигма стала популярной лишь в 90-х, когда «железо» стало к этому готово.

Java, как почти все современные языки – это объектно-ориентированный язык, на котором достаточно просто моделировать процессы реального мира, и пользоваться всеми преимуществами объектно-ориентированного подхода.

  • ООП используется во многих других языках программирования
  • широко использует абстракции
  • легко моделировать объекты реального мира
  • требует дополнительного изучения и развития абстрактного мышления

Функциональный

Когда необходимо уменьшить время выполнения программы, есть два очевидных пути:

  1. Оптимизировать программу;
  2. Увеличить частоту процессора.

С оптимизацией имеем следующие проблемы:

  • оптимизировать приходится ВСЕ программы;
  • существует логический лимит, дальше которого оптимизировать невозможно.

Ускорение процессора решает эти проблемы, и ускоряет выполнение сразу всех программ.

Благодаря закону Мура мир развивался вторым путём — ускорял процессоры. Закон гласил, что каждые два года частота процессоров обязана удваиваться. Но однажды закон Мура перестал работать и частота перестала расти. И мы перестали получать необходимое нам ускорение программ. Во всём сразу обвинили Мура, сказали, что он всё не так понял, и в закон внесли поправку: не частота удваивается, а количество транзисторов!

Таким образом последние годы частота процессоров не растёт, а растет количество транзисторов. Транзисторы расходуются на дополнительные ядра процессоров. Но если посмотреть на выше упомянутые два способа ускорения программ — там нет пункта о добавлении ядер. Чтобы программу можно было ускорить с помощью дополнительных ядер — она должна быть способна выполняться независимыми частями.

Но сделать это не так-то просто: все куски программ зависят друг от друга, зависят от общих данных (особенно если речь идёт об объектно-ориентированном программировании).

Читать еще:  Можно ли использовать айфон как флешку?

И тут на помощь приходит функциональное программирование, которое сводит к минимуму (а в идеале полностью исключает) использование общих данных, что позволяет легко и просто выполнять программу на разных ядрах.

Объектно-ориентированной парадигме потребовалось 20 лет, чтобы пройти путь от теории к массовому использованию. Зная, как стремительно сейчас изменяется наш мир, можно подумать, что это – исключение из правил, и мы принимаем всё новое гораздо быстрее и охотней.

Однако функциональной парадигме программирования потребовалось гораздо больше времени, чем объектно-ориентированной. Впервые эта парадигма была представлена в 30-е годы, однако в широкие массы функциональное программирование начинает входить только в наши дни.

Существуют полностью функциональные языки (Haskel, Erlang) и гибридные — сочетающие в себе объектно-ориентированный и функциональный подходы (Scala, C++).

Начиная с 8 версии Java приобретает механизмы функционального программирования (такие как ссылки на функции и лямбда-выражения), что позволяет легко создавать программы, которые могут выполняться на нескольких ядрах одновременно.

  • доступны новые приёмы программирования
  • легко создаются программы, способные использовать одновременно несколько ядер процессора
  • требует дополнительного изучения и развития функционального (математического) мышления

Типизация: строгая, статическая, явная

Строгая типизация

Судя из названия, если типизация строгая — то существуют какие-то правила, нарушать которые нельзя.

Если типизация НЕ строгая (например как в JavaScript), это не значит что правил нет. Правила есть, при чём есть ещё дополнительные правила, которые вступают в силу, когда нарушаются основные.

Пример (необходимо понимать что строки и числа — это разные типы данных):

Сложение двух чисел и двух строк, не зависимо от модели типизации, везде происходит одинаково:

Разница будет когда мы (возможно по ошибке) попытаемся сложить число и строку:

5 + «5» = ? (10 или «55»)

Строго типизированный язык скажет, что здесь затаилась ошибка, и заставит нас явно привести всё к какому-то одному типу.

Не строго типизированный начнёт хитрить: он прибегнет к дополнительному набору правил на случай не соответствия типов. В зависимости от этих правил будет выбран один из вариантов:

  1. Строка «5» станет числом, и результат будет 10 (сложение чисел)
  2. Число «5» станет строкой, и результат будет «55» (конкатенация строк)

Получается, что при не строгой типизации, по ошибке мы можем попытаться выполнить операцию над несовместимыми типами данных, и в зависимости от «дополнительных правил» получить разный результат: 10 или «55».

В Java используется строгий вариант, который предпочитает сообщить об ошибке и заставить программиста явно привести к какому-то типу – тем самым избежать набора «дополнительных правил», на случай, когда типы не совпадают.

  • нет дополнительных правил автоматического преобразования типов: их не нужно знать и нет ошибок неправильного преобразования
  • быстро приходит понимание типизации
  • все необходимые преобразования приходится выполнять явно

Поскольку типы всех переменных в Java определяются статически на этапе компиляции, то есть возможность проверить правильно ли эти типы использованы. Например, если мы пытаемся отправить автомобиль к ветеринару — Java нам скажет, что ветеринар не принимает объекты такого типа. Следовательно, об ошибке мы узнаем, как только попробуем скомпилировать код, а не когда запустим приложение на сервере.

Таким образом Java избегает целый класс ошибок (ошибок несовместимости типов), т.к. они все обнаруживаются во время компиляции благодаря статической типизации.

Естественно, что в наши дни никто не пишет код в блокноте, и не компилирует из командной строки — всё это умеют делать современные инструменты разработки IDE (IDEA, Eclipse, NetBeans). И все указанные IDE активно пользуются тем, что типизация статическая, и проверяют ошибки ещё до того, как мы попытаемся код скомпилировать.

Ещё одним плюсом статической типизации является то, что IDE способна подсказывать, какие методы и свойства есть у объекта. Это очень сильно упрощает и разработку, и обучение.

  • об ошибках несовместимых типов мы узнаём во время компиляции (с использованием IDE во время написания кода), а не во время выполнения программы
  • зная тип данных IDE может подсказывать, какие операции с ним можно выполнить (очень полезно, особенно на начальных этапах знакомства с языком)
  • необходимость определять типы самостоятельно

Явная типизация

Для того, чтобы объявить переменную в Java, необходимо явно указать её тип. Например, переменная i целочисленного типа объявляется так:

При этом на самом деле Java умеет вывести тип переменной i и без нашего int. Достаточно было бы написать:

Однако, Java не поддерживает объявление переменных с помощью var и, возможно, никогда не будет поддерживать.

  • необходимость указывать типы явно (микро-проблема)

Кросс-платформенный

Для того, чтобы написанное вами приложение могло запускаться на разных платформах (Linux, Windows, Android), оно должно быть преобразовано (скомпилированно) в совместимые с этой платформой процессорные инструкции.

Java декларирует, что для её программ этого не требуется. За счёт чего это достигается?

Код, написанный на Java, компилируется не в инструкции процессора (как у большинства компилируемых языков), а в специальный байт-код. Этот байт-код запускается на Java-машине — специальной программе, которая умеет преобразовать байт-код в процессорные инструкции.

Таким образом от платформы зависит не код, а Java-машина. Установив соответствующую Java-машину на каждую платформу, наш код будет одинаково работать на каждой из них.

  • программы могут работать на разных системах
  • страдает производительность (незначительно)

Сборщик мусора

Память. Она не резиновая. В процессе работы программы создаются объекты, загромождая память. На плечи программиста ложится бремя следить за этими объектами, и когда они становятся не нужны — удалять их. Задача не из простых. Если что-то пошло не так — образуется утечка памяти, и приложение неизбежно (это вопрос времени) остановится с ошибкой об исчерпании всей доступной памяти.

Так вот Java решает эту проблему с помощью сборщика мусора. Вы просто не должны думать о ненужных объектах, думайте только о нужных! А о не нужных позаботится сборщик. Сам. Без напоминаний.

Попутно сборщик решает ещё одну проблему — фрагментацию памяти. Если в двух словах, суть проблемы в следующем: есть кусок памяти на 10 ячеек, 5 из них заняты и 5 свободны. Вы хотите записать целый объект на 5 ячеек в память — но не можете сделать этого. Т.к. свободные ячейки расположены не подряд, а три вначале, и две в конце.

  • не нужно следить за объектами, и принимать решение об очистке памяти
  • нет проблемы фрагментации памяти

Hello world

Обзор языка был бы не полным без классического примера самой простой программы:

public class MyFirstClass <

public static void main(String[] args) <

System.out.println(“Hello world!”);

Из-за многословности этого, казалось бы, элементарного действия считают, что «порог входа» в Java слишком велик, и это отпугивает многих потенциальных пользователей этого языка. Действительно, hello world на Java окунает в ООП, заставляя задуматься, что такое класс. Почему он паблик? Зачем статик? Однако, на самом деле достаточно относиться первое время к этому как к магии и продолжать изучение этого замечательного языка.

И со временем Вам будут открыты все таинства заклинаний Java 🙂

Функциональное программирование: в Java и C# слишком много церемоний

Администратор

Группа: Главные администраторы
Сообщений: 14349
Регистрация: 12.10.2007
Из: Twilight Zone
Пользователь №: 1

  • О применении функционального стиля программирования в языке Java.
  • О некоторых базовых паттернах для работы с коллекциями данных из функционального программирования в примерах на Java.
  • Немного о библиотеке Google Collections.

Если вы программируете на языках Java, C#, C++, PHP, или любом другом ОО языке, хотели бы познакомиться с функциональным программированием, но не имеет возможности/желания изучать Haskell/Scala/Lisp/Python, — эта статья специально для вас.

Тем, кто знаком с функциональным программированием, но никогда не применял его в Java, думаю, это будет тоже интересно.

Вводим конструкцию «функция» в языке Java

Что такое функциональное программирование? Если в двух словах, то функциональное программирование — это программирование, в котором функции являются объектами, и их можно присваивать переменным, передавать в качестве аргументов другим функциям, возвращать в качестве результата от функций и т. п. Преимущества, которые раскрывает такая возможность, будут понятны чуть позже. Пока нам надо разобраться, как в Java можно использовать саму конструкцию «функция».

Как известно, в Java нету функций, там есть только классы, методы и объекты классов. Зато в Java есть анонимные классы, то есть классы без имени, которые можно объявлять прямо в коде любого метода. Этим мы и воспользуемся. Для начала объявим такой интерфейс:

public final interface Function <
T apply(F from);
>

Теперь в коде какого-нибудь метода мы можем объявить анонимную реализацию этого интерфейса:

public static void main() <
// Объявляем “функцию”, присваиваем ее переменной intToString.
Function intToString = new Function () <
@Override public String apply(Integer from) <
return from.toString();
>
>;

intToString.apply(9000); // Вызываем нашу функцию. Получаем строку “9000”.
>

Такую реализацию мы и будем называть «анонимной функцией». С точки зрения функционального программирования с ней можно делать все то же самое, что и с функцией из функциональных языков: присваивать переменным, передавать в качестве аргумента другим функциям(и методам классов), получать в качестве результата от функций(и методов классов).

Теперь можно перейти к изложению некоторых базовых паттернов функционального программирования.

Работа с коллекциями в функциональном стиле

Допустим, у нас есть некая коллекция целых чисел. Мы хотим их вывести на экран в виде строки, и каждое число в строке будет разделено через запятую. Нефункциональное решение выглядело бы примерно так:

public String joinNumbers(Collection numbers) <
StringBuilder result = new StringBuilder();
boolean first = true;
for (Integer number : numbers) <
if (first)
first = false;
else
result.append(“, “);
result.append(number);
>
return result;
>

Для реализации функционального решения нам потребуется сперва подготовить несколько функций и методов. Будем объявлять их в качестве статических полей класса:

public static final Function INT_TO_STRING = . // Уже реализовали выше

// Берет поэлементно значения из коллекции from, преобразует их с помощью функции transformer
// и возвращает список результатов преобразования в том же порядке.
public static List map(Collection from, Function transformer) <
ArrayList result = new ArrayList ();
for (F element : from)
result.add(transformer.apply(element));
return result;
>

// Берет коллекцию произвольных элементов и конкатенирует их в строку
public static String join(Collection from, String separator) <
StringBuilder result = new StringBuilder();
boolean first = true;
for (T element : from) <
if (first)
first = false;
else
result.append(separator);
result.append(element);
>
return result.toString();
>

Читать еще:  Старинное приспособление для пряжи

Теперь наш метод joinNumbers будет выглядить следующим образом:

public String joinNumbers(Collection numbers) <
return join(map(numbers, INT_TO_STRING), “, “);
>

Метод реализован ровно в одну простую строку.

Хотелось бы отметить несколько важных моментов:

  1. Методы map и join являются достаточно обобщенными, то есть их можно применять не только для решения данной задачи. Это значит, что их можно было бы выделить в некий утилитный класс, и использовать потом этот класс в разных частях проекта.
  2. Вместо класса Collection в методе map можно было бы передавать Iterable и возвращать новый Iterable, извлекая из переданной коллекции данные по мере обхода данных в возвращаемой коллекции, то есть извлекать элементы лениво, поэтапно, а не все сразу. Такая реализация, позволит, например, создавать цепочки преобразования данных, выделяя каждый этап преобразования в отдельную простую функцию, при этом эффективность алгоритма будет оставаться порядка O(n):

map(map(numbers, MULTIPLY_X_2), INT_TO_STRING); // каждый элемент умножаем на два и приводим к строке.

  • Создавая какой-нибудь класс, вы можете создавать для некоторых его методов статические поля, являющиеся функциями-обертками, делегирующими вызов apply на вызов соответствующего метода класса. Это позволит использовать «методы» объектов в функциональном стиле, например, в представленных выше конструкциях.
  • Работа с коллекциями с помощью Google Collections

    Ребята из Google как раз создали удобную библиотеку с утилитными классами, позволяющую работать с коллекциями в Java в функциональном стиле. Вот некоторые из возможностей, которые она предоставляет:

    • interface Function . Интерфейс, аналогичный приведенному мной выше.
    • Iterables.filter. Берет коллекцию и функцию-предикат(функцию, возвращающую булево значение). В ответ возвращает коллекцию, содержающую все элементы исходной, на которые указанная функция вернула true. Удобно, например, если мы хотим отсеить из коллекции все четные числа: Iterables.filter(numbers, IS_ODD);
    • Iterables.transform. Делает то же самое, что функция map в моем примере выше.
    • Functions.compose. Берет две функции. Возвращает новую функция — их композицию, то есть функцию, которая получает элемент, подает его во вторую функцию, результат подает в первую функцию, и полученный из первой функции результат возвращает пользователю. Композицию можно использовать, например, так: Iterables.transform(numbers, Functions.compose(INT_TO_STRING, MULTIPLY_X_2));

    В Google Collections конечно есть еще много других полезных вещей как для функционального программирования, так и для работы с коллекциями в императивном стиле.

    Ссылки

    • Статья в Википедии о функциональном программировании.
    • Google Guava, проект, частью которого является Google Collections.
    • Видеопрезентация Google Collections с Joshua Bloch.
    • Apache Commons Collections. Решает схожие с Google Collections задачи, но был написан под Java 4, то есть без полиморфизма.

    О чем хотелось бы рассказать еще

    Дорогие друзья, если вам понравилась моя статья, я с удовольствием напишу еще что-нибудь интересное о применении функционального программирования в Java и других императивных языках. Вот некоторые из вещей, о которых есть желание рассказать, но нету возможности изложить сразу в одной статье:

    1. Мутабельные и иммутабельные замыкания.
    2. Pattern-matcher.
    3. Монады.
    4. Распараллеливание с использованием функционального подхода.
    5. Комбинаторы парсеров.

    C# глазами Java

    Есть два подхода к сравнению языков программирования: религиозная война и «a нам всё равно». Я постараюсь втиснутся между ними и начну с общего. Ключевой особенностью и Java, и C# является автоматическое управление памятью. Конечно, оба языка из-за этого совершенно не подходят для написания ядра операционной системы, но зато существенно упрощают разработку прикладных программ, потому что:

    • остаётся меньше возможностей для memory leak;
    • не надо писать код для освобождения памяти;
    • можно написать f(g(x)) и не думать об освобождении памяти от результата g(x).

    Итак, мы имеем две массовых платформы для разработки программного обеспечения, на каждой из которых работают миллионы программистов; за каждой стоят мировые софтверные гиганты, но ни одна не имеет революционных преимуществ.

    Влияние Microsoft

    Исторически Java появилась раньше .NET и потихоньку захватывала рынок не только серверного ПО, но и GUI-приложений для корпоративных клиентов, потому что C++ сложноват для рисования формочек, Visual Basic не похож на язык для крутых девелоперов, а Borland инвестировал в Java больше, чем в Delphi.

    Но чем больше приложений на Java, тем меньше потребность в Windows, поэтому Microsoft решил не поддерживать Java, а создать .NET, чтобы стимулировать разработку программ для Windows. Кончено, какая-то кроссплатформенность у .NET есть, но, с точки зрения Windows, .NET стремится стать частью операционной системы, как Internet Explorer. Карьера .NET-разработчика предполагает тесные партнёрские отношения с Microsoft, включая использование среды разработки Visual Studio, базы данных MS SQL и системы контроля версий Visual SourceSafe.

    Нужно отдать должное маркетингу Microsoft, многие компании предпочитают думать о программном обеспечении не выходя за рамки видения Microsoft. Иногда из-за этого приходится откладывать в сторону любимую Java и брать в руки C#. Хорошая новость в том, что накопленный в Java опыт помогает и в .NET, а развитие .NET стимулирует прогресс Java.

    CVS vs. VSS

    Большинство Java-разработчиков привыкли к CVS, после этого переход на Visual SourceSafe в сочетании с реализацией интеграции с ним в Visual Studio и концепцией solutions-projects воспринимается весьма болезненно. Справедливости ради стоит отметить, что переход на CVS в большом проекте теоретически возможен, но вызовет крайне негативную реакцию людей, привыкших к VSS.

    В этом месте можно было бы немного помахать кулаками на тему «почему CVS лучше VSS», но я этого делать не буду, потому что CVS тоже не идеален, и есть такой проект как Subversion, который открыто позиционируется в качестве замены CVS. Microsoft тоже не считает VSS своим флагманским продуктом и готовит ему замену в виде Visual Studio 2005 Team System.

    Влияние VB.NET

    Программы на многих языках могут быть скомпилированы в байт-код для JVM, но практически абсолютно всё программное обеспечение для платформы Java написано именно на Java. Для .NET примерно с равной вероятностью проект может разрабатываться как на C#, так и на VB.NET, причём очень часто используются сразу оба языка.

    Понятно, что C# и VB.NET практически не имеют между собой отличий, кроме синтаксиса, но вносят раздробленность в сообщество разработчиков. Даже если использовать только на C#, то в результатах поиска по документации всегда будут путаться материалы, относящиеся к VB.NET. В десктоп-версии MSDN можно настроить фильтр по языку программирования, но всё равно, на мой вкус, документация по Java значительно удобней и понятней.

    Разработка GUI

    Разработка GUI на C# являет типичным примером RAD, как Delphi. На Java GUI, как правило, делается при помощи Swing. Хотя Swing весьма объёмен и сложен, хорошая продуманность и расширяемость архитектуры в сочетании с доступными исходными кодами позволяет разрабатывать GUI любой сложности.

    Разработка веб-приложений

    Я съел собаку на разработке веб-приложений на Java, но никогда не использовал ASP.NET; тем не менее, я вполне допускаю, что ASP.NET имеет определённые и весьма существенные преимущества при создании небольших сайтов. Однако, эти преимущества выделяют веб-приложения в отдельный сегмент, очень многие .NET-разработчики специализируются либо только на GUI, либо только на веб. На Java веб-приложения можно создавать без использования каких-либо специфических технологий вроде JSP, JSTL или Struts: extends HttpServlet — и вперёд!

    Конечно, рынок разработки сайтов Java без боя не отдаст, можно ожидать новостей от JavaServer Faces или от Fabrique. В любом случае, делать веб-странички — это не самый сложный класс задач для современных языков программирования.

    Is everything object?

    В Java очень популярен лозунг “Everything is object”, в C# это не так. Первое, что бросается в глаза — наличие структур в C#. Очевидно, что есть мотивы использовать структуры для повышения производительности, но мне кажется, что современные компьютеры достаточно производительны, чтобы не добавлять ещё одну сущность в язык.

    Также, вместо анонимных классов в C# используются делегаты, это такая идея о том, что если у метода есть определённый набор аргументов и заданный тип возвращаемого значения, то совершенно не важно, как он называется, является ли он статическим и прочие глупости — можно его дёргать.

    Если уж зашла речь о delegate , то нужно упомянуть и об event — они действительно сокращают размер кода при разработке GUI, хотя и ценой отступления от идей ООП.

    В определённой степени C# менее лаконичен, не вдаваясь в подробности, ограничусь упоминанием ключевых слов virtual , override , ref , out и param , не имеющих аналогов в Java.

    Влияние платформы на самосознание программистов

    Безусловно, больше всего на качество программного обеспечения влияет качество самих разработчиков, а не язык программирования. Тем не менее, мой опыт говорит о том, что в подавляющем большинстве проектов на Java для build management используется Ant, а в .NET очень часто билды делаются встроенными средствами Visual Studio, хотя аналогичные инструменты существуют и для .NET. Кроме этого, в C# нет чётких правил наименования классов и их размещения на диске, что часто вносит дополнительную путаницу (конечно, квалифицированные программисты успешно борются с этой проблемой).

    В С# нет checked exceptions, есть даже объяснение почему. Такое решение имеет свои резоны, но если компилятор не контролирует обработку checked exception, то нужно больше рассказывать об обработке ошибок через другие коммуникационные каналы, иначе появятся программисты, которые вообще не будут знать, что такое exception.

    Тигры рвутся вперёд

    Есть области, в которых Java доминирует безусловно, например, игры для мобильных телефонов или технология JavaCard. Однако, борьба между C# и Java за долю на рынке будет идти ещё долго, обе платформы будут совершенствоваться, например, в Java 5 и .NET 2.0 появится поддержка generics.

    Очевидно, что успех каждого конкретного проекта зависит не от языка программирования, а от понимания задачи, умения давать методам понятные названия, способности избегать дублирования кода и других общечеловеческих ценностей.

    Благодарности

    Огромное спасибо Дмитрию Жемерову, благодаря которому вам не пришлось читать всю ту ерунду, которую я написал сначала, компании DataArt, которая дала мне возможность заниматься изучением C# в рабочее время, коллегам из компании DataArt, которые оказывали мне интеллектуальную и моральную поддержку, а также компании JetBrains, которая очень вовремя начала делать ReSharper, который позволяет получать на C# многие виды удовольствия, привычные пользователям IntelliJ IDEA. Особая благодарность Алексею Пчелинцеву за заботу о букве Ё.

    голоса
    Рейтинг статьи
    Ссылка на основную публикацию
    Статьи c упоминанием слов: