Modern Java
Modern Java Language Features
You are viewing a free preview lesson.
Lesson Overview
Java language সময়ের সাথে অনেক evolve করেছে।
Modern Java-তে এমন কিছু language feature আছে যেগুলো repetitive syntax কমায় এবং intent আরও clearly express করতে সাহায্য করে।
Examples:
var
switch
as an expression।
"""
Text block
"""
এবং:
if (
value instanceof Course course
) {
...
}
এই features-এর purpose হলো:
কম code লেখা
শুধু তা নয়।
Better goal:
কম ceremony
+
clearer intent
+
safer code
এই lesson-এ আমরা শিখব:
- Local variable type inference with
var - কখন
varuseful - কখন explicit type better
- Modern
switchexpressions - Arrow-style
switch - Returning values from
switch yield- Multiple case labels
- Text blocks
- Multiline text
- Pattern matching with
instanceof - Pattern matching with
switch - Sealed type-এর high-level ধারণা
- Modern syntax এবং readability
- Modern features overuse না করা
Why Modern Language Features Matter
Consider:
Map<String, List<Course>> coursesByCategory =
new HashMap<String, List<Course>>();
Modern Java-তে generic inference ব্যবহার করে আমরা already লিখতে পারি:
Map<String, List<Course>> coursesByCategory =
new HashMap<>();
আর local variable-এর type initializer থেকে obvious হলে:
var coursesByCategory =
new HashMap<String, List<Course>>();
লেখাও possible।
Modern Java-এর অনেক feature একই philosophy follow করে:
Compiler যেটা reliably infer করতে পারে,
সেটার unnecessary ceremony কমাও।
কিন্তু:
readability sacrifice করো না।
Local Variable Type Inference with var
Java-তে local variable declare করার সময়:
var
ব্যবহার করা যায়।
Example:
var title =
"Java Foundation";
Compiler বুঝে:
title is String
var Is Not Dynamic Typing
এটি খুব important।
এই code:
var title =
"Java";
এর পরে title permanently:
String
type-এর variable।
এটি valid:
title =
"Backend";
এটি invalid:
title =
42;
কারণ compiler already inferred:
String
Java Is Still Statically Typed
var মানে:
variable-এর type নেই
না।
বরং:
type compiler infer করেছে
So conceptually:
var title =
"Java";
is equivalent in type meaning to:
String title =
"Java";
var Works Only with Local Variables
Typical use:
void process() {
var course =
findCourse();
}
var local variables-এর জন্য।
এটি class field declaration-এর general replacement নয়।
Example:
class CourseService {
var repository;
}
এভাবে field declare করা যায় না।
var Needs an Initializer
Compiler initializer দেখে type infer করে।
So this is invalid:
var course;
কারণ compiler জানে না type কী।
Need:
var course =
new Course(
"JAVA",
"Java Foundation"
);
var with Collections
Example:
var courses =
new ArrayList<Course>();
Compiler infers:
ArrayList<Course>
Interface Type vs Concrete Type
Compare:
List<Course> courses =
new ArrayList<>();
with:
var courses =
new ArrayList<Course>();
First version communicates:
আমি variable-টিকে List abstraction হিসেবে ব্যবহার করছি।
Second version inferred type:
ArrayList<Course>
এটি একটি subtle design difference।
var Can Change the Visible Abstraction
Suppose:
var courses =
new ArrayList<Course>();
Now reader sees concrete implementation।
Whereas:
List<Course> courses =
new ArrayList<>();
communicates:
Only List behavior matters.
So var সবসময় shorter হলেও better নয়।
Good var Example
var course =
repository.findByCode(
"JAVA"
).orElseThrow();
যদি surrounding code থেকে type obvious হয়, var noise কমাতে পারে।
Another Good Example
var formatter =
DateTimeFormatter.ofPattern(
"dd MMM yyyy"
);
Initializer থেকেই type clear।
Less Clear Example
var result =
service.process(
request
);
result কী?
Course?
List<Course>?
boolean?
ProcessingResult?
Reader-কে method definition দেখতে হতে পারে।
Explicit type clearer:
EnrollmentResult result =
service.process(
request
);
Practical Rule for var
Use var when:
initializer type obvious
variable name meaningful
type itself important information hide করছে না
Avoid when:
reader type বুঝতে পারছে না
generic API return type unclear
abstraction boundary important
var Should Reduce Noise, Not Information
Good:
var now =
Instant.now();
Clear।
Potentially less clear:
var data =
execute();
Both variable name এবং type ambiguous।
Problem var নয়।
Problem:
information loss
var with Diamond Operator
This can be problematic:
var values =
new ArrayList<>();
Without additional type context, inferred generic type may not be what you intended।
Better:
var values =
new ArrayList<String>();
or:
List<String> values =
new ArrayList<>();
The second is often clearer।
var and Null
This is invalid:
var course =
null;
Compiler cannot infer a useful type from only null।
var and Method Return Types
Example:
var courses =
loadCourses();
This compiles if method return type known।
But readability question remains:
Is return type obvious enough here?
Use judgment।
Traditional switch
Suppose:
enum CourseStatus {
DRAFT,
PUBLISHED,
ARCHIVED
}
Traditional switch:
String label;
switch (
status
) {
case DRAFT:
label =
"Draft";
break;
case PUBLISHED:
label =
"Published";
break;
case ARCHIVED:
label =
"Archived";
break;
default:
throw new IllegalStateException();
}
এখানে অনেক ceremony:
temporary variable
assignment
break
Modern Java switch expressions এটিকে cleaner করতে পারে।
Switch Expression
String label =
switch (
status
) {
case DRAFT ->
"Draft";
case PUBLISHED ->
"Published";
case ARCHIVED ->
"Archived";
};
এখন পুরো switch একটি value produce করছে।
Statement vs Expression
Traditional switch often used as:
statement
Modern switch can be:
expression
Meaning:
switch itself returns a value
Why This Is Useful
Instead of:
String result;
switch (...) {
...
}
we can directly write:
String result =
switch (...) {
...
};
This reduces mutable intermediate state।
Arrow-Style Cases
Modern syntax:
case DRAFT ->
"Draft";
Arrow form-এর advantage:
no accidental fall-through
no break needed
Traditional Fall-Through Problem
Old switch:
switch (
value
) {
case 1:
System.out.println(
"One"
);
case 2:
System.out.println(
"Two"
);
}
If value == 1, lack of break means execution may continue into case 2।
Arrow-style switch এই accidental fall-through avoid করে।
Multiple Labels in One Case
Suppose:
enum Role {
ADMIN,
INSTRUCTOR,
LEARNER,
SUPPORT
}
Group:
String area =
switch (
role
) {
case ADMIN,
SUPPORT ->
"Operations";
case INSTRUCTOR ->
"Teaching";
case LEARNER ->
"Learning";
};
Multiple labels comma দিয়ে combine করা যায়।
Switch with Multiple Statements
Suppose one case-এ multiple statements দরকার।
String message =
switch (
status
) {
case DRAFT -> {
System.out.println(
"Preparing draft message"
);
yield "Course is still a draft.";
}
case PUBLISHED ->
"Course is available.";
case ARCHIVED ->
"Course is archived.";
};
yield
Switch expression-এর block case থেকে result দিতে:
yield
ব্যবহার করা হয়।
Example:
case DRAFT -> {
String message =
buildMessage();
yield message;
}
yield Is Not return
return current method থেকে বের হয়ে যায়।
yield current switch expression-এর value provide করে।
Example:
return switch (
status
) {
...
};
Inside a block:
yield value;
switch-এর result।
Switch Expression and Exhaustiveness
যখন compiler জানে possible cases finite, যেমন enum, সব cases handle করলে default প্রয়োজন নাও হতে পারে।
Example:
switch (
status
) {
case DRAFT -> ...
case PUBLISHED -> ...
case ARCHIVED -> ...
}
এটি useful কারণ future-এ enum-এ নতুন value যোগ হলে compiler কিছু switch expressions update করার প্রয়োজন detect করতে পারে।
Avoid Unnecessary default for Closed Enum Logic
Suppose:
enum Status {
ACTIVE,
CANCELLED
}
If you write:
switch (
status
) {
case ACTIVE ->
"Active";
default ->
"Other";
}
Future:
PAUSED
add হলে code silently:
Other
দেবে।
কিন্তু explicit cases:
switch (
status
) {
case ACTIVE ->
"Active";
case CANCELLED ->
"Cancelled";
}
future change compiler-visible হতে পারে।
Closed domain states-এ exhaustive handling valuable।
Switch Is Not Always Better Than if
Suppose:
if (
score >= 80
) {
...
}
A switch force করার দরকার নেই।
Use switch when logic naturally depends on:
discrete alternatives
Examples:
enum
known command types
sealed hierarchy
specific values
Text Blocks
Multiline String লেখার জন্য modern Java provides:
Text Blocks
Traditional:
String message =
"Hello\n"
+ "Welcome to LiveKlass\n"
+ "Learn Java";
Text block:
String message =
"""
Hello
Welcome to LiveKlass
Learn Java
""";
Why Text Blocks Matter
Multiline content-এর ক্ষেত্রে traditional escaped Strings noisy হতে পারে।
Examples:
JSON
SQL
HTML
email templates
test fixtures
documentation text
Text blocks এগুলো readable করতে পারে।
JSON Example
Traditional:
String json =
"{\n"
+ " \"code\": \"JAVA\",\n"
+ " \"title\": \"Java Foundation\"\n"
+ "}";
Text block:
String json =
"""
{
"code": "JAVA",
"title": "Java Foundation"
}
""";
Much easier to read।
SQL Example
String query =
"""
SELECT
id,
code,
title
FROM courses
WHERE status = ?
ORDER BY title
""";
Even though this course does not teach database programming, text blocks-এর use case বোঝার জন্য এটি useful example।
HTML Example
String html =
"""
<html>
<body>
<h1>Welcome</h1>
</body>
</html>
""";
Text Blocks Are Still Strings
A text block has type:
String
So:
String message =
"""
Hello
World
""";
is normal String value।
You can call:
message.length();
or:
message.contains(
"Hello"
);
Text Blocks Do Not Mean Template Engine
Example:
"""
Hello {name}
"""
Java automatically {name} replace করবে না।
Text block শুধু multiline String syntax।
Dynamic values still need an explicit approach।
Example:
String message =
"""
Hello %s
Welcome to the course.
""".formatted(
name
);
.formatted()
Example:
String message =
"""
Course: %s
Price: %d
""".formatted(
course.title(),
course.priceInPaisa()
);
This can be useful for simple formatting।
Avoid Building Complex Templates Manually
Large:
HTML
emails
documents
শুধু text block + string formatting দিয়ে maintain করা difficult হতে পারে।
Text blocks useful, কিন্তু proper template system-এর replacement নয়।
Pattern Matching with instanceof
Traditional Java:
if (
value instanceof Course
) {
Course course =
(Course) value;
System.out.println(
course.title()
);
}
Notice duplication:
check type
then cast same type
Modern pattern matching simplifies this।
Modern instanceof
if (
value instanceof Course course
) {
System.out.println(
course.title()
);
}
Here:
course
automatically typed as:
Course
inside the valid scope।
Mental Model
value instanceof Course course
means:
value কি Course?
যদি হয়,
তাহলে সেটিকে Course হিসেবে course নাম দিয়ে use করো।
No Manual Cast Needed
Old:
Course course =
(Course) value;
Modern pattern matching avoids this duplicated cast।
Pattern Variable Scope
Example:
if (
value instanceof Course course
) {
System.out.println(
course.title()
);
}
course is usable where compiler knows the pattern matched।
Outside that valid scope, it may not exist।
Pattern Matching with Conditions
Example:
if (
value instanceof Course course
&& course.published()
) {
System.out.println(
course.title()
);
}
This works naturally।
Why?
Because right side of && runs only if:
value is Course
so course is known there।
Useful Guard-Style Code
Instead of:
if (
!(value instanceof Course)
) {
return;
}
Course course =
(Course) value;
modern Java can express:
if (
!(value instanceof Course course)
) {
return;
}
System.out.println(
course.title()
);
Compiler tracks where the pattern variable is safely available।
Pattern Matching with switch
Modern switch can also match types।
Suppose:
interface Notification {
}
Implementations:
record EmailNotification(
String email
) implements Notification {
}
record SmsNotification(
String phone
) implements Notification {
}
Then conceptually:
String destination =
switch (
notification
) {
case EmailNotification email ->
email.email();
case SmsNotification sms ->
sms.phone();
};
This lets switch branch based on runtime type while binding a typed variable।
Why Pattern Switch Can Be Useful
Without it:
if (
notification instanceof EmailNotification email
) {
...
} else if (
notification instanceof SmsNotification sms
) {
...
}
For a closed set of variants, switch can communicate:
handle each possible shape
more clearly।
Pattern Switch Is Not a Replacement for Polymorphism
Suppose each notification can send itself:
interface Notification {
void send();
}
Then:
notification.send();
may be much better than:
switch (
notification
) {
case EmailNotification ...
case SmsNotification ...
}
When Pattern Matching Fits Better
Pattern switch is useful when behavior:
belongs to the operation
rather than naturally to each subtype।
Example:
formatting for a report
external serialization
cross-cutting inspection
one-off transformation
If subtype-specific behavior belongs inside the type itself, polymorphism may be cleaner।
Sealed Types — High-Level Idea
Sometimes we want an inheritance hierarchy where only specific implementations are allowed।
Conceptually:
PaymentResult
├── PaymentSucceeded
├── PaymentFailed
└── PaymentPending
If the allowed variants are intentionally closed, Java supports:
sealed types
Example
sealed interface PaymentResult
permits PaymentSucceeded,
PaymentFailed {
}
Then:
record PaymentSucceeded(
String paymentId
) implements PaymentResult {
}
and:
record PaymentFailed(
String reason
) implements PaymentResult {
}
Why Sealed Types Are Useful
A sealed hierarchy communicates:
Only these known variants may represent this concept.
This can combine nicely with exhaustive pattern matching।
Example conceptually:
String message =
switch (
result
) {
case PaymentSucceeded success ->
"Paid: "
+ success.paymentId();
case PaymentFailed failure ->
"Failed: "
+ failure.reason();
};
Closed Domain States
This works well for concepts like:
Command result
Payment result
Validation result
Message type
Workflow event variant
when valid implementations are intentionally limited।
Sealed Types Are Not Always Needed
Do not make every interface sealed।
If extension is expected:
plugins
third-party implementations
open framework contracts
a normal interface may be better।
Use sealed types when:
closed hierarchy
is part of the domain design।
Enum vs Sealed Hierarchy
If state needs only names:
enum CourseStatus {
DRAFT,
PUBLISHED,
ARCHIVED
}
is excellent।
If each variant carries different data:
Success → paymentId
Failure → reason
sealed hierarchy + records may model the domain better।
Modern Switch with Enum
Example:
enum CourseStatus {
DRAFT,
PUBLISHED,
ARCHIVED
}
String action =
switch (
status
) {
case DRAFT ->
"Continue editing";
case PUBLISHED ->
"View course";
case ARCHIVED ->
"Restore unavailable";
};
Very direct mapping।
Modern Switch with Complex Calculation
long discount =
switch (
learnerType
) {
case STANDARD ->
0;
case STUDENT ->
price / 10;
case PREMIUM -> {
long calculated =
price / 5;
yield Math.min(
calculated,
100_000
);
}
};
A block is useful when one branch needs multiple statements।
Avoid Huge Switch Branches
If each case contains:
30 lines
validation
network call
file handling
complex business rules
switch expression becomes hard to read।
Extract methods:
return switch (
command.type()
) {
case CREATE ->
handleCreate(
command
);
case UPDATE ->
handleUpdate(
command
);
case DELETE ->
handleDelete(
command
);
};
Modern Syntax Should Reveal Intent
Good modern Java:
var now =
Instant.now();
String label =
switch (
status
) {
case DRAFT ->
"Draft";
case PUBLISHED ->
"Published";
case ARCHIVED ->
"Archived";
};
if (
value instanceof Course course
) {
...
}
These reduce ceremony without hiding meaning।
Modern Syntax Can Also Hide Meaning
Consider:
var x =
service.execute(
a,
b,
c
);
Reader has little idea:
what x is
what execute returns
what this operation means
The solution is not:
never use var
It is:
preserve useful information.
Explicit Type Can Be Documentation
Example:
Optional<Course> course =
repository.findByCode(
code
);
The type communicates:
Course may be absent
Compare:
var course =
repository.findByCode(
code
);
This removes that immediate signal।
Both compile।
First may be more educational/readable।
Domain Types Deserve Visibility
If a type communicates important meaning:
Money
CourseCode
EnrollmentResult
Optional<Course>
Duration
Instant
showing the type can improve readability।
var Is Great for Verbose Mechanical Types
Example:
var iterator =
courses.iterator();
or:
var formatter =
DateTimeFormatter.ofPattern(
"dd MMM yyyy"
);
The initializer tells the story।
Modern Java and Immutability
Many modern features work nicely with immutable style।
Example:
String label =
switch (
status
) {
...
};
Instead of:
String label =
null;
switch (...) {
label = ...;
}
Less mutable intermediate state।
Modern Features and Records
We have already used:
record
in previous lessons।
Example:
record CourseSummary(
String code,
String title
) {
}
Records reduce boilerplate for value-oriented data models।
We will study records more directly in the next lesson।
Practical Example — Status Description
public class Main {
public static void main(String[] args) {
var status =
CourseStatus.PUBLISHED;
var message =
description(
status
);
System.out.println(
message
);
}
static String description(
CourseStatus status
) {
return switch (
status
) {
case DRAFT ->
"Course is being prepared.";
case PUBLISHED ->
"Course is available.";
case ARCHIVED ->
"Course is no longer active.";
};
}
enum CourseStatus {
DRAFT,
PUBLISHED,
ARCHIVED
}
}
Practical Example — Pattern Matching
public class Main {
public static void main(String[] args) {
printLength(
"Java"
);
printLength(
42
);
}
static void printLength(
Object value
) {
if (
value instanceof String text
) {
System.out.println(
text.length()
);
}
}
}
No explicit cast required।
Practical Example — Text Block
public class Main {
public static void main(String[] args) {
String course =
"Java Foundation";
String message =
"""
Welcome to LiveKlass
Course: %s
Learn consistently.
Build deliberately.
""".formatted(
course
);
System.out.println(
message
);
}
}
Practical Example — Sealed Result
public class Main {
public static void main(String[] args) {
PaymentResult result =
new PaymentSucceeded(
"PAY-1001"
);
String message =
describe(
result
);
System.out.println(
message
);
}
static String describe(
PaymentResult result
) {
return switch (
result
) {
case PaymentSucceeded success ->
"Payment succeeded: "
+ success.paymentId();
case PaymentFailed failure ->
"Payment failed: "
+ failure.reason();
};
}
sealed interface PaymentResult
permits PaymentSucceeded,
PaymentFailed {
}
record PaymentSucceeded(
String paymentId
) implements PaymentResult {
}
record PaymentFailed(
String reason
) implements PaymentResult {
}
}
Common Mistake 1 — Thinking var Means Dynamic Type
Wrong mental model:
আজ String
কাল Integer
Java var does not work like that।
Type compile time-এই fixed।
Common Mistake 2 — Using var Everywhere
This:
var a =
doSomething();
var b =
process(
a
);
var c =
transform(
b
);
may make type flow difficult to understand।
Use explicit types where they provide important context।
Common Mistake 3 — Unclear Variable Names with var
Bad combination:
var x =
load();
Much better:
var publishedCourses =
loadPublishedCourses();
or explicit:
List<Course> courses =
loadPublishedCourses();
Common Mistake 4 — Assuming Switch Expression Needs break
Arrow-style:
case DRAFT ->
"Draft";
does not use:
break
Common Mistake 5 — Using return Instead of yield
Inside a multi-statement switch-expression case:
case DRAFT -> {
...
yield value;
}
yield provides switch result।
return would return from the enclosing method।
Common Mistake 6 — Adding default Without Thinking
For a closed enum, a broad:
default
can hide newly added enum constants।
Explicit exhaustive cases can make future changes more visible।
Common Mistake 7 — Using Switch for Complex Business Workflows
A switch with huge cases may indicate responsibilities should be moved to:
methods
strategies
polymorphic objects
services
depending on design।
Common Mistake 8 — Thinking Text Blocks Are Templates
Text blocks only make multiline String syntax easier।
They do not automatically provide:
escaping policy
HTML templating
conditional rendering
template variables
Common Mistake 9 — Using Pattern Matching Instead of Polymorphism Everywhere
If every subtype already knows how to perform an operation:
notification.send();
may be better than external type switching।
Pattern matching is useful, but not a replacement for good object design।
Common Mistake 10 — Sealing Every Interface
Sealed types are appropriate only when a hierarchy is intentionally closed।
Open extension points should remain open when required।
Practice 1 — Infer the Type
var name =
"Sakib";
What is the type?
Answer
String
Practice 2
var count =
10;
Type?
Answer
int
Practice 3 — Valid or Invalid?
var value;
Answer
Invalid।
Initializer না থাকায় type infer করা যায় না।
Practice 4
var value =
null;
Answer
Invalid।
Useful type infer করার মতো initializer নেই।
Practice 5 — Choose var or Explicit Type
repository.findByCode(
code
)
returns Optional<Course>।
Which may communicate more information?
Answer
Often:
Optional<Course> course =
repository.findByCode(
code
);
because absence semantics immediately visible।
var-ও valid, but may hide useful type information।
Practice 6 — Switch Expression
Convert:
CourseStatus.PUBLISHED
to:
"Published"
using switch।
Solution
String label =
switch (
status
) {
case DRAFT ->
"Draft";
case PUBLISHED ->
"Published";
case ARCHIVED ->
"Archived";
};
Practice 7 — Multiple Case Labels
Suppose:
enum Level {
BEGINNER,
INTERMEDIATE,
ADVANCED
}
Beginner and Intermediate should return:
"Core"
Advanced:
"Specialized"
Solution
String category =
switch (
level
) {
case BEGINNER,
INTERMEDIATE ->
"Core";
case ADVANCED ->
"Specialized";
};
Practice 8 — yield
When do we need yield?
Answer
যখন switch expression-এর একটি arrow case block:
case X -> {
...
}
multiple statements execute করে এবং শেষে একটি value provide করতে হয়।
Practice 9 — Text Block
Create multiline:
Hello
Java
Solution
String value =
"""
Hello
Java
""";
Practice 10 — Pattern Matching
Convert:
if (
value instanceof String
) {
String text =
(String) value;
}
Solution
if (
value instanceof String text
) {
...
}
Practice 11 — Pattern with Condition
Check value is non-empty String।
Solution
if (
value instanceof String text
&& !text.isBlank()
) {
...
}
Practice 12 — Enum or Sealed Hierarchy?
Need:
DRAFT
PUBLISHED
ARCHIVED
with no different payload per state।
Answer
Usually:
enum
is simpler।
Practice 13
Need:
Success contains paymentId
Failure contains reason
Answer
A sealed hierarchy with different record variants can be a good fit।
Practice 14 — Pattern Matching or Polymorphism?
Every Notification subtype already knows how to send itself।
Best starting point?
Answer
Prefer:
notification.send();
through polymorphism rather than switching on subtype externally।
Practice 15 — Modern Syntax Goal
What is the main reason to use modern Java features?
Answer
Not simply fewer characters।
The goal is:
reduce unnecessary ceremony
while preserving or improving readability and correctness
True or False
varmakes Java dynamically typed.varvariables still have a compile-time type.varcan be used without an initializer.varshould always replace explicit local types.- Switch expressions can produce a value.
- Arrow-style switch cases require
break. yieldcan provide a value from a switch-expression block.- Text blocks are still
Stringvalues. - Text blocks automatically behave as template engines.
- Pattern matching with
instanceofcan eliminate repeated casts. - Pattern matching should replace all polymorphism.
- Sealed types can model intentionally closed hierarchies.
- Enums are still useful in modern Java.
- A broad
defaultcase can sometimes hide newly added enum states. - Modern syntax should be chosen primarily for readability.
Answers
1. False
2. True
3. False
4. False
5. True
6. False
7. True
8. True
9. False
10. True
11. False
12. True
13. True
14. True
15. True
Knowledge Check
Question 1
var আসলে কী করে?
Question 2
কেন var dynamic typing নয়?
Question 3
কখন explicit type var-এর চেয়ে clearer হতে পারে?
Question 4
Switch expression traditional switch থেকে কীভাবে আলাদা?
Question 5
Arrow-style switch-এর advantage কী?
Question 6
yield কী কাজ করে?
Question 7
Text block কেন useful?
Question 8
Pattern matching with instanceof কী boilerplate remove করে?
Question 9
Pattern matching এবং polymorphism-এর relationship কী?
Question 10
Sealed type কী ধরনের hierarchy model করতে useful?
Question 11
Enum এবং sealed hierarchy-এর মধ্যে practical difference কী?
Question 12
Modern language features ব্যবহার করার সবচেয়ে important principle কী?
Knowledge Check Answers
Answer 1
var initializer দেখে local variable-এর compile-time type infer করে।
Example:
var title =
"Java";
Compiler infer করে:
String
Answer 2
কারণ type inference-এর পরে variable-এর type fixed থাকে।
var value =
"Java";
এর পরে:
value =
10;
valid নয়।
Answer 3
যখন type নিজেই important information communicate করে।
Examples:
Optional<Course>
Instant
Duration
EnrollmentResult
অথবা initializer থেকে return type obvious নয়।
Answer 4
Modern switch একটি expression হিসেবে value produce করতে পারে।
Example:
String label =
switch (
status
) {
...
};
Traditional switch সাধারণত control-flow statement হিসেবে বেশি ব্যবহৃত হতো।
Answer 5
Arrow-style cases accidental fall-through avoid করে এবং break boilerplate প্রয়োজন হয় না।
Answer 6
একটি multi-statement switch-expression case block থেকে switch-এর result value provide করে।
Answer 7
Multiline Strings যেমন JSON, SQL, HTML বা long messages readableভাবে লিখতে সাহায্য করে।
Answer 8
Repeated:
instanceof
check-এর পরে explicit cast:
(Type) value
লিখতে হয় না।
Answer 9
Pattern matching subtype inspect করার concise tool।
কিন্তু behavior naturally subtype-এর responsibility হলে polymorphic method call often better।
Pattern matching polymorphism-এর replacement নয়।
Answer 10
যেখানে valid subtypes intentionally limited এবং known।
Example:
Success
Failure
style result hierarchy।
Answer 11
enum ভালো যখন variants মূলত fixed named states।
Sealed hierarchy useful যখন প্রতিটি variant আলাদা type এবং আলাদা data carry করতে পারে।
Answer 12
Feature modern বা shorter বলে ব্যবহার করা নয়।
Use it when it:
reduces ceremony
clarifies intent
preserves type meaning
improves maintainability
Practical Modern Java Guide
Use var when:
initializer clearly reveals type
explicit type adds little information
Use explicit type when:
type communicates domain meaning
return type is not obvious
abstraction matters
Use switch expression when:
one input state maps to one result
Use text block when:
multiline String readability matters
Use instanceof pattern matching when:
type check followed by cast is required
Use sealed hierarchy when:
allowed subtypes are intentionally closed
Use polymorphism when:
behavior naturally belongs to each subtype
Core Mental Model
Modern Java features-এর উদ্দেশ্য:
Code clever করা নয়।
Unnecessary ceremony কমানো।
For example:
Old:
if (
value instanceof Course
) {
Course course =
(Course) value;
...
}
Modern:
if (
value instanceof Course course
) {
...
}
Old:
String label;
switch (
status
) {
case DRAFT:
label =
"Draft";
break;
...
}
Modern:
String label =
switch (
status
) {
case DRAFT ->
"Draft";
...
};
Important principle:
Remove repetition,
not meaning.
Lesson Summary
এই lesson-এ আমরা Modern Java-এর কিছু গুরুত্বপূর্ণ language features শিখেছি।
আমরা শিখেছি:
varlocal variable type inference support করেvarJava-কে dynamically typed করে না- Compiler initializer থেকে actual static type determine করে
varinitializer ছাড়া ব্যবহার করা যায় নাvarসব জায়গায় explicit type replace করা উচিত নয়- Important domain type visible রাখা readability improve করতে পারে
- Switch expression directly value produce করতে পারে
- Arrow-style switch accidental fall-through avoid করে
- Multiple case labels combine করা যায়
- Multi-statement switch case থেকে
yieldদিয়ে value দেওয়া যায় - Exhaustive enum handling future changes detect করতে সাহায্য করতে পারে
- Text blocks multiline Strings readable করে
- Text blocks normal
String, template engine নয় instanceofpattern matching type check এবং cast combine করে- Pattern variable safe scope-এ directly ব্যবহার করা যায়
- Pattern matching with switch closed variants handle করতে useful
- Pattern matching polymorphism replace করে না
- Sealed types intentionally closed inheritance hierarchy model করতে পারে
- Enum simple fixed states-এর জন্য এখনো excellent choice
- Sealed hierarchy variants different data carry করলে useful হতে পারে
- Modern Java syntax use করার goal হলো clarity, শুধু short code নয়
সবচেয়ে important rule:
Modern Java ব্যবহার করুন
যখন language feature
intent clearer করে।
শুধু modern দেখানোর জন্য নয়।
Next Lesson
পরবর্তী lesson:
Records and Modern Data Models
আমরা শিখব:
recordকী- Record components
- Generated constructor
- Accessor methods
equals()hashCode()toString()- Compact constructors
- Validation
- Defensive copying
- Immutable data modeling
- Records এবং value objects
- Record vs normal class
- কখন Record appropriate
- কখন Record inappropriate
- Domain entities এবং value objects-এর difference